REST API Reference
Base URL: https://rng.dev/api/v1
Endpoints
GET /current
Returns the most recent generated round, including all inputs for verification.
Response:
{
"round": 12345678,
"output_hash": "a3f2e8c9d1b4a5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0",
"die_value": 4,
"generated_at": "2026-03-09T15:00:00Z",
"status": "complete",
"sources_available": 6,
"sources_total": 6,
"inputs": {
"aptos": "12345678:0xabc123...:0xdef456...",
"bitcoin": "00000000000000000002a7c4...3f:831245:def4567890abc...",
"cardano": "123456789:abc...:ghi7891234def...",
"ethereum": "0x8a3f2e...b9:19234567:0x1a2b3c4d5e6f...",
"solana": "245678901:5eykt4Uy...Gno:5VERv8NMvzbJMEkV...",
"sui": "12345678:abc123...:def789..."
}
}
Response Fields
| Field | Description |
|---|---|
output_hash | SHA3-256 hash of combined blockchain inputs |
die_value | Die value (1-6) derived from hash using rejection sampling |
inputs | Combined block hash and transaction ID inputs for each chain |
The inputs field contains the exact strings used to generate output_hash. Each chain's input includes block data and transaction ID in the format specified in How It Works. See Verification Guide to verify any round independently.
GET /round/{round_number}
Returns a specific historical round, including all inputs for verification.
Parameters:
| Name | Type | Description |
|---|---|---|
round_number | integer | The round number to fetch |
Example:
curl https://rng.dev/api/v1/round/12345678
Response:
{
"round": 12345678,
"output_hash": "a3f2e8c9d1b4a5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0",
"die_value": 4,
"generated_at": "2026-03-09T15:00:00Z",
"status": "complete",
"sources_available": 6,
"sources_total": 6,
"inputs": {
"aptos": "12345678:0xabc123...:0xdef456...",
"bitcoin": "00000000000000000002a7c4...3f:831245:def4567890abc...",
"cardano": "123456789:abc...:ghi7891234def...",
"ethereum": "0x8a3f2e...b9:19234567:0x1a2b3c4d5e6f...",
"solana": "245678901:5eykt4Uy...Gno:5VERv8NMvzbJMEkV...",
"sui": "12345678:abc123...:def789..."
}
}
GET /simple
Returns just the current die value as plain text.
Response:
4
Useful for simple integrations or shell scripts:
DIE=$(curl -s https://rng.dev/api/v1/simple)
echo "The die shows: $DIE"
GET /health
Returns service health status.
Response:
{
"status": "healthy",
"version": "1.0.0",
"last_round": 12345678,
"last_round_at": "2026-03-09T15:00:00Z",
"sources": {
"aptos": "ok",
"bitcoin": "ok",
"cardano": "ok",
"ethereum": "ok",
"solana": "ok",
"sui": "ok"
}
}
GET /health/gaps
Returns information about any missing rounds in the sequence.
Response:
{
"has_gaps": false,
"total_rounds": 12345678,
"missing_rounds": [],
"last_checked": "2026-03-09T15:00:00Z"
}
Response with gaps:
{
"has_gaps": true,
"total_rounds": 12345678,
"missing_rounds": [12345600, 12345601],
"gap_reason": "source_unavailability",
"last_checked": "2026-03-09T15:00:00Z"
}
GET /meta
Returns static metadata about the beacon service. Call once and cache — this data rarely changes.
Response:
{
"version": "2.0.0",
"sources": ["aptos", "bitcoin", "cardano", "ethereum", "solana", "sui"],
"explorers": {
"aptos": "https://explorer.aptoslabs.com/block/{block}",
"bitcoin": "https://mempool.space/block/{hash}",
"cardano": "https://cardanoscan.io/block/{block}",
"ethereum": "https://etherscan.io/block/{block}",
"solana": "https://solscan.io/block/{slot}",
"sui": "https://suiscan.xyz/mainnet/checkpoint/{checkpoint}"
},
"tx_explorers": {
"aptos": "https://explorer.aptoslabs.com/txn/{txid}",
"bitcoin": "https://mempool.space/tx/{txid}",
"cardano": "https://cardanoscan.io/transaction/{txid}",
"ethereum": "https://etherscan.io/tx/{txid}",
"solana": "https://solscan.io/tx/{txid}",
"sui": "https://suiscan.xyz/mainnet/tx/{txid}"
},
"input_format": {
"aptos": "{block_height}:{block_hash}:{txid}",
"bitcoin": "{block_height}:{block_hash}:{txid}",
"cardano": "{slot}:{block_hash}:{txid}",
"ethereum": "{block_number}:{block_hash}:{txid}",
"solana": "{slot}:{blockhash}:{txid}",
"sui": "{checkpoint}:{digest}:{txid}"
},
"tx_selection": {
"aptos": { "index": 0, "description": "First transaction" },
"bitcoin": { "index": 1, "description": "Second transaction (skip coinbase)" },
"cardano": { "index": 0, "description": "First transaction" },
"ethereum": { "index": 0, "description": "First transaction" },
"solana": { "index": 0, "description": "First transaction" },
"sui": { "index": 0, "description": "First transaction" }
},
"combination_order": ["aptos", "bitcoin", "cardano", "ethereum", "solana", "sui"],
"combination_separator": "|",
"hash_algorithm": "SHA3-256"
}
Use explorers templates to build verification links from inputs values.
Statistics Endpoints
GET /stats/distribution
Returns die value distribution statistics.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
rounds | integer | 1000 | Number of recent rounds to analyze |
Response:
{
"rounds_analyzed": 1000,
"distribution": {
"1": 168,
"2": 165,
"3": 167,
"4": 166,
"5": 167,
"6": 167
},
"expected": 166.67,
"chi_squared": {
"statistic": 0.072,
"p_value": 0.9995,
"degrees_of_freedom": 5
},
"status": "PASS"
}
GET /stats/streaks
Returns streak distribution analysis.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
rounds | integer | 1000 | Number of recent rounds to analyze |
Response:
{
"rounds_analyzed": 1000,
"streaks": {
"1": 833,
"2": 139,
"3": 23,
"4": 4,
"5": 1
},
"expected_geometric": {
"1": 833.3,
"2": 138.9,
"3": 23.1,
"4": 3.9,
"5": 0.6
},
"status": "PASS"
}
GET /stats/transitions
Returns transition matrix between consecutive die values.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
rounds | integer | 1000 | Number of recent rounds to analyze |
Response:
{
"rounds_analyzed": 1000,
"matrix": [
[28, 27, 28, 28, 28, 28],
[27, 28, 27, 28, 28, 27],
[28, 28, 27, 28, 27, 28],
[27, 28, 28, 27, 28, 28],
[28, 27, 28, 28, 27, 28],
[28, 28, 28, 27, 28, 27]
],
"expected": 27.78,
"chi_squared": {
"statistic": 0.36,
"p_value": 1.0,
"degrees_of_freedom": 25
},
"status": "PASS"
}
GET /stats/autocorrelation
Returns autocorrelation analysis for sequence independence.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
lags | integer | 20 | Number of lag values to compute |
Response:
{
"rounds_analyzed": 10000,
"autocorrelations": {
"1": 0.003,
"2": -0.002,
"3": 0.001,
"...": "...",
"20": -0.001
},
"confidence_bound": 0.02,
"significant_lags": [],
"status": "PASS"
}
GET /stats/randomness
Comprehensive randomness statistics for monitoring and AI agents.
Response:
{
"_meta": {
"schema_version": "1.0",
"generated_at": "2026-03-09T15:00:00Z",
"beacon_round": 12345678
},
"summary": {
"overall_status": "PASS",
"plain_english": "The beacon is behaving like a fair random source with no detectable bias."
},
"rolling_windows": {
"last_100": { "...": "..." },
"last_1000": { "...": "..." },
"last_100000": { "...": "..." }
},
"comparisons": {
"beacon_vs_drand": {
"ks_statistic": 0.012,
"p_value": 0.87,
"status": "PASS"
},
"beacon_vs_nist": {
"ks_statistic": 0.011,
"p_value": 0.84,
"status": "PASS"
}
}
}
Comparison Endpoints
GET /comparisons
Compares beacon die value distributions against reference sources (drand, NIST) using the Kolmogorov-Smirnov two-sample test. This validates that our randomness is statistically indistinguishable from established random beacons.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
rounds | integer | 1000 | Number of recent samples to compare (max 100,000) |
Response:
{
"sample_counts": {
"beacon": 5000,
"drand": 5000,
"nist": 5000
},
"pairwise_comparisons": [
{
"source1": "beacon",
"source2": "drand",
"statistic": 0.0089,
"p_value": 0.5012,
"effect_size": 0.0089,
"n1": 5000,
"n2": 5000,
"interpretation": "Distributions are statistically indistinguishable",
"status": "PASS"
},
{
"source1": "beacon",
"source2": "nist",
"statistic": 0.0156,
"p_value": 0.8234,
"effect_size": 0.0156,
"n1": 5000,
"n2": 5000,
"interpretation": "Distributions are statistically indistinguishable",
"status": "PASS"
},
{
"source1": "drand",
"source2": "nist",
"statistic": 0.0167,
"p_value": 0.7654,
"effect_size": 0.0167,
"n1": 5000,
"n2": 5000,
"interpretation": "Distributions are statistically indistinguishable",
"status": "PASS"
}
],
"uniformity_tests": [
{
"source": "beacon",
"statistic": 0.0023,
"p_value": 0.9999,
"effect_size": 0.0023,
"n": 5000,
"interpretation": "Distribution consistent with uniform",
"status": "PASS"
},
{
"source": "drand",
"statistic": 0.0021,
"p_value": 0.9999,
"effect_size": 0.0021,
"n": 5000,
"interpretation": "Distribution consistent with uniform",
"status": "PASS"
},
{
"source": "nist",
"statistic": 0.0312,
"p_value": 0.7234,
"effect_size": 0.0312,
"n": 5000,
"interpretation": "Distribution consistent with uniform",
"status": "PASS"
}
],
"overall_status": "PASS",
"plain_english": "Compared 5,000 samples from each source. All distributions are statistically indistinguishable — beacon randomness matches known reference sources."
}
Note: Sample counts are automatically matched to the minimum available across all sources for fair comparison. If you request 100,000 rounds but NIST only has 5,000, all sources will be compared using 5,000 samples each.
Response Fields
| Field | Description |
|---|---|
sample_counts | Number of die values available from each source |
pairwise_comparisons | K-S tests between each pair of sources |
uniformity_tests | K-S tests against theoretical uniform distribution (1-6) |
overall_status | Combined status: PASS, WATCH, or INVESTIGATE |
plain_english | Human-readable summary of the comparison |
Status Values
Status is determined by effect size, not p-values, making it reliable at any sample size:
| Status | Effect Size | Meaning |
|---|---|---|
PASS | < 0.10 | Negligible/weak difference — no action needed |
WATCH | 0.10 - 0.20 | Moderate difference — monitor for patterns |
INVESTIGATE | > 0.20 | Strong difference — review for potential issues |
Reference Sources
| Source | Description | Update Frequency |
|---|---|---|
| drand | League of Entropy distributed randomness | Every 10 seconds |
| NIST | NIST Randomness Beacon 2.0 | Every 60 seconds |
Reference Endpoints
GET /reference/drand
Returns the current status and recent die values from the drand (League of Entropy) reference source.
Response:
{
"source": "drand",
"total_rounds": 76543,
"latest_round": 4521234,
"recent_die_values": [3, 1, 6, 2, 4, 5, 1, 3, 6, 2]
}
Response Fields
| Field | Description |
|---|---|
source | Source identifier ("drand") |
total_rounds | Total number of drand rounds we've collected |
latest_round | Most recent drand round number |
recent_die_values | Last 10 die values (1-6) derived from drand randomness |
GET /reference/nist
Returns the current status and recent die values from the NIST Randomness Beacon 2.0.
Response:
{
"source": "nist",
"total_rounds": 1234,
"latest_round": 1709730,
"recent_die_values": [5, 2, 4, 1, 6, 3, 2, 5, 1, 4]
}
Response Fields
| Field | Description |
|---|---|
source | Source identifier ("nist") |
total_rounds | Total number of NIST pulses we've collected |
latest_round | Most recent NIST pulse index |
recent_die_values | Last 10 die values (1-6) derived from NIST randomness |
Response Codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad request (invalid parameters) |
| 404 | Round not found |
| 429 | Rate limit exceeded |
| 500 | Server error |
| 503 | Service unavailable (generation paused) |
Authentication
API Key Format
Include your API key in the Authorization header using Bearer token format:
Authorization: Bearer YOUR_API_KEY
Code Examples
curl:
curl -H "Authorization: Bearer $RNG_API_KEY" \
https://rng.dev/api/v1/current
JavaScript (fetch):
const response = await fetch('https://rng.dev/api/v1/current', {
headers: {
'Authorization': `Bearer ${process.env.RNG_API_KEY}`
}
});
const data = await response.json();
Python (requests):
import os
import requests
response = requests.get(
'https://rng.dev/api/v1/current',
headers={'Authorization': f'Bearer {os.environ["RNG_API_KEY"]}'}
)
data = response.json()
Environment Setup
Store your API key in a .env file for local development:
# .env
RNG_API_KEY=rng_sk_your_key_here
Then load it in your application:
# Shell
source .env && curl -H "Authorization: Bearer $RNG_API_KEY" https://rng.dev/api/v1/current
// Node.js - install dotenv: npm install dotenv
require('dotenv').config();
// process.env.RNG_API_KEY is now available
# Python - install python-dotenv: pip install python-dotenv
from dotenv import load_dotenv
load_dotenv()
# os.environ["RNG_API_KEY"] is now available
Self-Hosted Setup
If running your own instance of rng.dev, API keys are managed through the admin interface. Keys are stored as SHA-256 hashes in the api_keys table.
To generate a key programmatically:
import secrets
import hashlib
# Generate a new API key
key = f"rng_sk_{secrets.token_hex(16)}"
key_hash = hashlib.sha256(key.encode()).hexdigest()
# Store key_hash in database, give key to user (only shown once)
print(f"API Key: {key}")
Rate Limiting
| Tier | Limit |
|---|---|
| Unauthenticated | 10 requests/hour |
| Authenticated | 100,000 requests/day |
Need higher limits? Contact us.
Rate Limit Headers
All responses include rate limit information:
X-RateLimit-Limit: 100000
X-RateLimit-Remaining: 99423
X-RateLimit-Reset: 1709996400
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in current period |
X-RateLimit-Remaining | Requests remaining before limit is reached |
X-RateLimit-Reset | Unix timestamp when the limit resets |
Handling Rate Limits
When rate limited, you'll receive a 429 response:
{
"detail": "Rate limit exceeded. Maximum 10 requests per hour."
}
Implement exponential backoff or respect the Retry-After header:
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status !== 429) return response;
const retryAfter = response.headers.get('Retry-After') || (i + 1) * 1000;
await new Promise(r => setTimeout(r, retryAfter));
}
throw new Error('Rate limit exceeded after retries');
}
Status Values
| Status | Description |
|---|---|
finalized | All 8 blockchain sources contributed |
confirmed | 6-7 sources contributed |
partial | 4-5 sources contributed |
degraded | 2-3 sources contributed (use with caution) |
failed | Round could not be generated (< 2 sources) |
missed | Round was skipped (historical gap) |
Error Responses
{
"error": {
"code": "ROUND_NOT_FOUND",
"message": "Round 99999999 does not exist",
"details": {
"requested_round": 99999999,
"latest_round": 12345678
}
}
}
CORS
The API supports CORS for browser-based applications:
- Allowed origins:
*(all origins) - Allowed methods:
GET, OPTIONS - Allowed headers:
Content-Type, Authorization
OpenAPI Specification
Full OpenAPI 3.0 specification available at:
- Swagger UI: https://api.rng.dev/docs
- ReDoc: https://api.rng.dev/redoc
- JSON: https://api.rng.dev/openapi.json