For developers & agents
PickRandom API
Every tool on this site is also a JSON endpoint. The API is free, requires no key or sign-up, and is CORS-open — call it straight from a browser, a script, a cron job, or an AI agent. All randomness is cryptographically secure (crypto.getRandomValues with rejection sampling — no modulo bias, no Math.random()), and responses are never cached.
There are no hard rate limits, so please be gentle: batch with the count parameter instead of looping single requests. Invalid input always returns HTTP 400 with a JSON {"error": "..."} body — the endpoints never fail with an HTML error page.
Prefer machine-readable docs? The full spec lives at /api/v1/openapi.json (OpenAPI 3.1), and a plain-text overview for AI agents is in /llms.txt.
Base URL — https://www.pickrandom.app
01
GET /api/v1/number
Random integers in an inclusive range. Set unique=true to draw without replacement (count must not exceed the range size).
| Parameter | Type | Default | Description |
|---|---|---|---|
| min | integer | 1 | Lower bound (inclusive), within ±10^15. |
| max | integer | 100 | Upper bound (inclusive), within ±10^15; must be ≥ min. |
| count | integer | 1 | How many numbers to draw, 1–1000. |
| unique | boolean | false | Draw without repeats. Requires count ≤ range size. |
Request
curl "https://www.pickrandom.app/api/v1/number?min=1&max=100&count=3&unique=true"
Response
{
"results": [42, 7, 88],
"min": 1,
"max": 100
}02
POST /api/v1/pick
Pick one or more random items from a list you send. Unique by default (a partial Fisher–Yates); set unique to false to allow repeats.
| Parameter | Type | Default | Description |
|---|---|---|---|
| items | string[] | required | 1–10,000 strings; total payload ≤ 1 MB. |
| count | integer | 1 | How many items to pick, 1–1000. |
| unique | boolean | true | No repeats. Requires count ≤ items.length. |
Request
curl -X POST "https://www.pickrandom.app/api/v1/pick" \
-H "Content-Type: application/json" \
-d '{"items": ["alice", "bob", "carol", "dave"], "count": 2}'Response
{
"results": ["carol", "alice"]
}03
POST /api/v1/shuffle
Return the whole list in a uniformly random order (unbiased Fisher–Yates).
| Parameter | Type | Default | Description |
|---|---|---|---|
| items | string[] | required | 1–10,000 strings; total payload ≤ 1 MB. |
Request
curl -X POST "https://www.pickrandom.app/api/v1/shuffle" \
-H "Content-Type: application/json" \
-d '{"items": ["red", "green", "blue"]}'Response
{
"results": ["blue", "red", "green"]
}04
GET /api/v1/coin
Fair 50/50 coin flips.
| Parameter | Type | Default | Description |
|---|---|---|---|
| count | integer | 1 | How many flips, 1–1000. |
Request
curl "https://www.pickrandom.app/api/v1/coin?count=3"
Response
{
"results": ["heads", "tails", "heads"]
}05
GET /api/v1/dice
Roll standard dice, from a d2 to a d100, with the total precomputed.
| Parameter | Type | Default | Description |
|---|---|---|---|
| sides | integer | 6 | One of 2, 4, 6, 8, 10, 12, 20, 100. |
| count | integer | 1 | How many dice to roll, 1–100. |
Request
curl "https://www.pickrandom.app/api/v1/dice?sides=20&count=2"
Response
{
"results": [17, 4],
"total": 21,
"sides": 20
}06
GET /api/v1/yes-or-no
An unbiased yes-or-no answer. Add maybe=true for a three-way split.
| Parameter | Type | Default | Description |
|---|---|---|---|
| maybe | boolean | false | Include “maybe” as a third, equally likely outcome. |
Request
curl "https://www.pickrandom.app/api/v1/yes-or-no"
Response
{
"result": "yes"
}07
GET /api/v1/password
A cryptographically secure password with at least one character from each enabled set. Generated per request and never stored or logged.
| Parameter | Type | Default | Description |
|---|---|---|---|
| length | integer | 16 | Password length, 4–256. |
| uppercase | boolean | true | Include A–Z. |
| lowercase | boolean | true | Include a–z. |
| numbers | boolean | true | Include 0–9. |
| symbols | boolean | true | Include punctuation symbols. At least one set must be enabled. |
Request
curl "https://www.pickrandom.app/api/v1/password?length=24&symbols=false"
Response
{
"result": "vN3kQ8pXbR2mW7cJ1sT5yZ0d",
"length": 24
}Provably fair
Verifiable draws
For raffles where participants should not have to trust the operator, the API offers a two-step commit–reveal draw: commit (the server generates a secret seed and returns its SHA-256 commitment), publish (you post the commitment where participants can see it, and optionally collect a client_seed from them), then reveal (the server opens the seed and derives the winner deterministically). Because the seed was committed before anyone saw the client seed, the server cannot re-roll — and the reveal response includes everything a third party needs to recompute the winner.
The protocol is stateless: nothing is stored server-side. The encrypted seal returned by commit is the state — send it back unchanged at reveal time. Note: these two endpoints return HTTP 503 on deployments where the DRAW_SECRET environment variable is not configured.
Step 01
POST /api/v1/draw/commit
No body required. Returns the commitment to publish and an opaque seal that only this server can open. Publish the commitment to participants before revealing.
Request
curl -X POST "https://www.pickrandom.app/api/v1/draw/commit"
Response
{
"commitment": "9f2ce2…64-char lowercase hex…41b7",
"seal": "wN3kQ…opaque base64, keep it for the reveal…Zg==",
"algorithm": { "name": "commit-reveal-hmac-sha256-v1", "…": "…" },
"expires": null,
"next": "POST /api/v1/draw/reveal",
"note": "Publish the commitment to participants BEFORE revealing."
}Step 02
POST /api/v1/draw/reveal
Opens the seal, verifies the seed still hashes to the published commitment, and derives the winner — revealing the server seed, the HMAC, and the exact formula for third-party audit.
| Parameter | Type | Default | Description |
|---|---|---|---|
| seal | string | required | The seal from /api/v1/draw/commit, unchanged (at most 4,096 characters). |
| commitment | string | required | The published commitment — a 64-character lowercase hex string. |
| items | string[] | required | 1–10,000 strings; total payload ≤ 1 MB. Order matters — it is part of the HMAC message. |
| client_seed | string | "" | Optional participant-contributed entropy (at most 256 characters), collected after the commitment was published. |
Request
curl -X POST "https://www.pickrandom.app/api/v1/draw/reveal" \
-H "Content-Type: application/json" \
-d '{
"seal": "wN3kQ…Zg==",
"commitment": "9f2ce2…41b7",
"items": ["alice", "bob", "carol"],
"client_seed": "tweet-1808991234"
}'Response
{
"winner": "carol",
"winnerIndex": 2,
"serverSeed": "e3d1a0…64-char lowercase hex…77af",
"commitment": "9f2ce2…41b7",
"clientSeed": "tweet-1808991234",
"algorithm": { "name": "commit-reveal-hmac-sha256-v1", "…": "…" },
"verify": {
"message": "9f2ce2…41b7\ntweet-1808991234\n[\"alice\",\"bob\",\"carol\"]",
"hmacHex": "5b09fc…64-char lowercase hex…c2d4",
"computation": "winnerIndex = BigInt(\"0x\" + hmacHex.slice(0, 16)) % BigInt(3) = 2, …"
}
}Verify it yourself
Anyone can audit a draw with three checks, no trust in this server required: the commitment equals sha256(serverSeed) (the 64-character hex string itself, not the decoded bytes); the HMAC message is commitment + "\n" + clientSeed + "\n" + JSON.stringify(items); and the winner index is the first 8 bytes of HMAC-SHA256(serverSeed, message) read as a big-endian unsigned 64-bit integer, mod the number of items.
The reveal response repeats this recipe in its algorithm and verify fields, so an auditor never needs this page.
Node.js — verification
import { createHash, createHmac } from "node:crypto";
// Inputs: the reveal response fields, plus the commitment you saw published.
const { serverSeed, clientSeed } = revealResponse;
const items = ["alice", "bob", "carol"]; // the exact list, in the exact order
// 1. The revealed seed must hash back to the published commitment.
// (The seed is a 64-char hex STRING — hash the string, not decoded bytes.)
const commitment = createHash("sha256").update(serverSeed).digest("hex");
// commitment === the one published before the draw ✓
// 2. Recompute the winner from the seed, the client seed, and the items.
const message = commitment + "\n" + clientSeed + "\n" + JSON.stringify(items);
const hmacHex = createHmac("sha256", serverSeed).update(message).digest("hex");
// 3. First 8 bytes of the HMAC as a big-endian unsigned 64-bit integer,
// reduced mod items.length.
const winnerIndex = Number(BigInt("0x" + hmacHex.slice(0, 16)) % BigInt(items.length));
// winnerIndex === revealResponse.winnerIndex ✓ items[winnerIndex] === winner ✓In your code
JavaScript & Python
No SDK needed — the API is plain HTTP and JSON. Here are the number and pick endpoints from JavaScript fetch and Python requests.
JavaScript — fetch
const res = await fetch(
"https://www.pickrandom.app/api/v1/number?min=1&max=100&count=5"
);
const { results } = await res.json();
console.log(results); // e.g. [42, 7, 88, 13, 66]const res = await fetch("https://www.pickrandom.app/api/v1/pick", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ items: ["alice", "bob", "carol"], count: 1 }),
});
const { results } = await res.json();
console.log(results[0]); // e.g. "bob"Python — requests
import requests
res = requests.get(
"https://www.pickrandom.app/api/v1/number",
params={"min": 1, "max": 100, "count": 5},
)
print(res.json()["results"]) # e.g. [42, 7, 88, 13, 66]import requests
res = requests.post(
"https://www.pickrandom.app/api/v1/pick",
json={"items": ["alice", "bob", "carol"], "count": 1},
)
print(res.json()["results"][0]) # e.g. "bob"Use with AI agents
Built for tool calls
These endpoints are documented in /llms.txt and are safe to call from agent tools: every request is stateless and side-effect free, no authentication or key management is needed, CORS is open, and errors come back as machine-readable JSON with a 400 status. If your agent needs a fair coin flip, an unbiased pick, or a secure password, point it here instead of letting the model improvise randomness.
Model Context Protocol
MCP server
PickRandom is also an MCP server at POST /api/mcp — JSON-RPC 2.0 over streamable HTTP, fully stateless (no sessions, no authentication), with the same validation limits and CSPRNG outcomes as the REST endpoints. Point any MCP client at https://www.pickrandom.app/api/mcp and it gets 7 tools:
pick_random · shuffle · random_number · flip_coin · roll_dice · yes_or_no · generate_password
Add it to your MCP client configuration (Claude Code, Cursor, and friends) as a remote HTTP server:
{
"mcpServers": {
"pickrandom": {
"type": "http",
"url": "https://www.pickrandom.app/api/mcp"
}
}
}Initialize
curl -s "https://www.pickrandom.app/api/mcp" \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {"name": "curl", "version": "0.0.0"}
}}'Call a tool
curl -s "https://www.pickrandom.app/api/mcp" \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {
"name": "roll_dice",
"arguments": {"sides": 20, "count": 2}
}}'