{"openapi":"3.1.0","info":{"title":"PickRandom API","version":"1.0.0","description":"Free, keyless JSON API for cryptographically secure randomness: random numbers, list picks, shuffles, coin flips, dice rolls, yes-or-no answers, passwords, and provably fair commit–reveal draws. Every outcome is drawn from a CSPRNG (crypto.getRandomValues with rejection sampling — no modulo bias, never Math.random()). No authentication or sign-up, CORS-open, and result responses are never cached. Invalid input always returns HTTP 400 with a JSON {\"error\": \"...\"} body. There are no hard rate limits — please batch with the count parameter instead of looping single requests."},"servers":[{"url":"https://www.pickrandom.app"}],"paths":{"/api/v1/number":{"get":{"operationId":"randomNumber","summary":"Random integers in an inclusive range","description":"Generates uniform random integers in [min, max]. Set unique=true to draw without replacement (count must not exceed the range size).","tags":["Randomness"],"parameters":[{"name":"min","in":"query","required":false,"description":"Lower bound (inclusive), within ±1e+15.","schema":{"type":"integer","minimum":-1000000000000000,"maximum":1000000000000000,"default":1}},{"name":"max","in":"query","required":false,"description":"Upper bound (inclusive), within ±1e+15; must be ≥ min.","schema":{"type":"integer","minimum":-1000000000000000,"maximum":1000000000000000,"default":100}},{"name":"count","in":"query","required":false,"description":"How many numbers to draw, 1–1000.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"unique","in":"query","required":false,"description":"Draw without repeats; requires count ≤ range size. Accepts true/false, 1/0, or yes/no (case-insensitive).","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Random integers plus the effective bounds.","content":{"application/json":{"schema":{"type":"object","required":["results","min","max"],"properties":{"results":{"type":"array","items":{"type":"integer"}},"min":{"type":"integer"},"max":{"type":"integer"}}}}}},"400":{"description":"Invalid input. The body is always JSON — never an HTML error page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/pick":{"post":{"operationId":"pickRandom","summary":"Pick random items from a list","description":"Picks one or more items uniformly at random from a list you send. Unique by default (a partial Fisher–Yates); set unique to false to allow repeats.","tags":["Randomness"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10000,"description":"1–10,000 strings; total request payload must be 1 MB or smaller."},"count":{"type":"integer","minimum":1,"maximum":1000,"default":1,"description":"How many items to pick, 1–1000."},"unique":{"type":"boolean","default":true,"description":"No repeats; requires count ≤ items.length."}}}}}},"responses":{"200":{"description":"The picked items.","content":{"application/json":{"schema":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Invalid input. The body is always JSON — never an HTML error page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/shuffle":{"post":{"operationId":"shuffleList","summary":"Shuffle a list","description":"Returns the whole list in a uniformly random order (unbiased Fisher–Yates).","tags":["Randomness"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10000,"description":"1–10,000 strings; total request payload must be 1 MB or smaller."}}}}}},"responses":{"200":{"description":"The same items in random order.","content":{"application/json":{"schema":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Invalid input. The body is always JSON — never an HTML error page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/coin":{"get":{"operationId":"flipCoin","summary":"Flip fair coins","description":"Fair 50/50 coin flips.","tags":["Randomness"],"parameters":[{"name":"count","in":"query","required":false,"description":"How many flips, 1–1000.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}}],"responses":{"200":{"description":"One entry per flip.","content":{"application/json":{"schema":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"type":"string","enum":["heads","tails"]}}}}}}},"400":{"description":"Invalid input. The body is always JSON — never an HTML error page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/dice":{"get":{"operationId":"rollDice","summary":"Roll standard dice","description":"Rolls standard dice (d2–d100) with the total precomputed.","tags":["Randomness"],"parameters":[{"name":"sides","in":"query","required":false,"description":"Sides per die — one of 2, 4, 6, 8, 10, 12, 20, 100.","schema":{"type":"integer","enum":[2,4,6,8,10,12,20,100],"default":6}},{"name":"count","in":"query","required":false,"description":"How many dice to roll, 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":1}}],"responses":{"200":{"description":"Each roll, the total, and the die size.","content":{"application/json":{"schema":{"type":"object","required":["results","total","sides"],"properties":{"results":{"type":"array","items":{"type":"integer","minimum":1}},"total":{"type":"integer"},"sides":{"type":"integer","enum":[2,4,6,8,10,12,20,100]}}}}}},"400":{"description":"Invalid input. The body is always JSON — never an HTML error page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/yes-or-no":{"get":{"operationId":"yesOrNo","summary":"Unbiased yes-or-no answer","description":"An unbiased yes-or-no answer. Add maybe=true for a three-way split including \"maybe\".","tags":["Randomness"],"parameters":[{"name":"maybe","in":"query","required":false,"description":"Include \"maybe\" as a third, equally likely outcome. Accepts true/false, 1/0, or yes/no (case-insensitive).","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"The answer.","content":{"application/json":{"schema":{"type":"object","required":["result"],"properties":{"result":{"type":"string","enum":["yes","no","maybe"]}}}}}},"400":{"description":"Invalid input. The body is always JSON — never an HTML error page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/password":{"get":{"operationId":"generatePassword","summary":"Generate a secure password","description":"A cryptographically secure password with at least one character from each enabled set. Generated per request and never stored or logged. At least one character set must be enabled.","tags":["Randomness"],"parameters":[{"name":"length","in":"query","required":false,"description":"Password length, 4–256.","schema":{"type":"integer","minimum":4,"maximum":256,"default":16}},{"name":"uppercase","in":"query","required":false,"description":"Include A–Z. Accepts true/false, 1/0, or yes/no (case-insensitive).","schema":{"type":"boolean","default":true}},{"name":"lowercase","in":"query","required":false,"description":"Include a–z. Accepts true/false, 1/0, or yes/no (case-insensitive).","schema":{"type":"boolean","default":true}},{"name":"numbers","in":"query","required":false,"description":"Include 0–9. Accepts true/false, 1/0, or yes/no (case-insensitive).","schema":{"type":"boolean","default":true}},{"name":"symbols","in":"query","required":false,"description":"Include punctuation symbols. Accepts true/false, 1/0, or yes/no (case-insensitive).","schema":{"type":"boolean","default":true}}],"responses":{"200":{"description":"The generated password.","content":{"application/json":{"schema":{"type":"object","required":["result","length"],"properties":{"result":{"type":"string"},"length":{"type":"integer","minimum":4,"maximum":256}}}}}},"400":{"description":"Invalid input. The body is always JSON — never an HTML error page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/draw/commit":{"post":{"operationId":"drawCommit","summary":"Provably fair draw — step 1 (commit)","description":"Step 1 of a provably fair commit–reveal draw. Generates a secret server seed and returns its SHA-256 commitment plus an encrypted seal holding the seed. The protocol is stateless — nothing is stored server-side; the seal IS the state. Publish the commitment to participants, optionally collect a client_seed from them, then call POST /api/v1/draw/reveal. No request body is required (an optional JSON object body is ignored).","tags":["Verifiable draws"],"responses":{"200":{"description":"The commitment to publish and the seal to keep for the reveal.","content":{"application/json":{"schema":{"type":"object","required":["commitment","seal","algorithm","expires","next","note"],"properties":{"commitment":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"SHA-256 hex digest of the server seed hex string. Publish this BEFORE revealing."},"seal":{"type":"string","maxLength":4096,"description":"Opaque base64 blob (AES-256-GCM-encrypted server seed). Send it back unchanged to /api/v1/draw/reveal."},"algorithm":{"type":"object","description":"Machine-readable description of the commit–reveal scheme (name, seed/commitment/seal encodings, and the exact winner_index formula) so auditors do not need to read the source.","required":["name","server_seed","commitment","seal","winner_index"],"properties":{"name":{"type":"string","const":"commit-reveal-hmac-sha256-v1"},"server_seed":{"type":"string"},"commitment":{"type":"string"},"seal":{"type":"string"},"winner_index":{"type":"string"}}},"expires":{"type":"null","description":"Always null — seals do not expire."},"next":{"type":"string","const":"POST /api/v1/draw/reveal"},"note":{"type":"string"}}}}}},"503":{"description":"Verifiable draws are not configured on this deployment (DRAW_SECRET unset).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/draw/reveal":{"post":{"operationId":"drawReveal","summary":"Provably fair draw — step 2 (reveal)","description":"Step 2 of a provably fair commit–reveal draw. Opens the seal from /api/v1/draw/commit, verifies the seed still hashes to the published commitment, and derives the winner deterministically — revealing everything (server seed, HMAC, formula) a third party needs to audit the draw: message = commitment + \"\\n\" + client_seed + \"\\n\" + JSON.stringify(items); winnerIndex = (first 8 bytes of HMAC-SHA256(key: UTF-8 bytes of the server seed hex string, message), read as a big-endian unsigned 64-bit integer) mod items.length.","tags":["Verifiable draws"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["seal","commitment","items"],"properties":{"seal":{"type":"string","minLength":1,"maxLength":4096,"description":"The seal returned by /api/v1/draw/commit, unchanged."},"commitment":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"The published commitment (64-character lowercase hex)."},"items":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10000,"description":"1–10,000 strings; total request payload must be 1 MB or smaller."},"client_seed":{"type":"string","maxLength":256,"default":"","description":"Optional participant-contributed entropy, collected AFTER the commitment was published."}}}}}},"responses":{"200":{"description":"The winner plus everything a third party needs to recompute it.","content":{"application/json":{"schema":{"type":"object","required":["winner","winnerIndex","serverSeed","commitment","clientSeed","algorithm","verify"],"properties":{"winner":{"type":"string","description":"items[winnerIndex]."},"winnerIndex":{"type":"integer","minimum":0,"description":"First 8 bytes of the HMAC as a big-endian unsigned 64-bit integer, mod items.length."},"serverSeed":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"The revealed server seed; SHA-256 of this string equals the commitment."},"commitment":{"type":"string","pattern":"^[0-9a-f]{64}$"},"clientSeed":{"type":"string"},"algorithm":{"type":"object","description":"Machine-readable description of the commit–reveal scheme (name, seed/commitment/seal encodings, and the exact winner_index formula) so auditors do not need to read the source.","required":["name","server_seed","commitment","seal","winner_index"],"properties":{"name":{"type":"string","const":"commit-reveal-hmac-sha256-v1"},"server_seed":{"type":"string"},"commitment":{"type":"string"},"seal":{"type":"string"},"winner_index":{"type":"string"}}},"verify":{"type":"object","required":["message","hmacHex","computation"],"properties":{"message":{"type":"string","description":"The exact HMAC input: commitment + \"\\n\" + clientSeed + \"\\n\" + JSON.stringify(items)."},"hmacHex":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Hex of HMAC-SHA256(server seed hex string, message)."},"computation":{"type":"string","description":"Human-readable restatement of the winnerIndex derivation."}}}}}}}},"400":{"description":"Invalid input, an invalid or corrupted seal, or a seal that does not match the commitment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Verifiable draws are not configured on this deployment (DRAW_SECRET unset).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Human-readable explanation of what was invalid."}}}}},"tags":[{"name":"Randomness","description":"Stateless CSPRNG-backed randomness endpoints."},{"name":"Verifiable draws","description":"Provably fair commit–reveal draws whose winners any third party can recompute."}]}