Public API
The data behind the public pages is a read-only JSON API at https://app.roundbeat.com/api. No key, no sign-in. The examples below are real mainnet responses captured on 13 Oct 2026 (a snapshot, not live), trimmed to the fields that matter.
Basics
- Base URL
https://app.roundbeat.com. Every path starts with/api.- Methods
GETonly. Responses are JSON, gzip-compressed when you ask for it.- Errors
- A 4xx with
{"error": "…"}: 400 for a bad parameter (an unknown module, an invalid slot), 404 for something that does not exist. - Modules
- A module parameter takes the ID or a slug:
1/curated(alsocurated-v1),2/simpledvt(alsodvt),3/csm,4/curated-v2(alsocmv2). An unknown value is a 400. - Operator IDs
- Unique only inside a module. Always pass
moduleIdto the operator endpoints; without it the API merges that ID across modules and answers with the headerWarning: 299 - "moduleId required". - Time windows
timetakes 1h, 6h, 24h, 7d or 30d; anything else means all time. An operator’s proposals and events lists echo the window they applied astime(nullfor all time).- Numbers
- ETH amounts are numbers in ETH. Wei and gwei amounts (balances, rewards, bids) are strings, so they keep full precision. Some counts and epochs are strings too, as shown.
- Caching
- The aggregate endpoints are cached on the server (overview 2 minutes, module summaries 2 minutes, health 1 minute, migration 5 minutes) and send
Cache-ControlandETag; repeat a request withIf-None-Matchto get a 304. Polling faster than the cache gains nothing. - Browsers
- The API does not send CORS headers for other sites, so a web page on another domain cannot call it from the browser. Call it from a server, a script or curl.
Network
Data freshness
GET /api/status
How far Roundbeat’s beacon node trails the wall clock. stale turns true when it is more than 64 slots behind; the app then shows its “Chain data delayed” banner.
curl -s 'https://app.roundbeat.com/api/status'{
"network": "mainnet",
"dataFreshness": {
"beaconHeadSlot": 15421335,
"expectedSlot": 15421335,
"lagSlots": 0,
"stale": false,
"staleSince": null,
"checkedAt": "2026-10-13T08:27:33.683378348Z",
"known": true
}
}Network overview
GET /api/indexed/overview
Lido-wide totals, per-module validator counts and how far indexing trails the head (lag, in epochs). liveOperators counts operators with validators on the beacon chain; operators counts every registered operator, including those with none yet or none left. depositedKeys is the keys Lido has deposited to, and totalValidators the Lido validators on the beacon chain; both include exited ones. alerts counts events by severity, all time and over the last 24 h, from beacon-chain events only: the event feed also counts on-chain contract events, so its totals can be higher. The response also lists the latest events.
curl -s 'https://app.roundbeat.com/api/indexed/overview'{
"network": "mainnet",
"overview": {
"epoch": 481915,
"operators": 793,
"liveOperators": 509,
"activeValidators": 233680,
"totalValidators": 493140,
"depositedKeys": 502022,
"totalEffectiveEth": 9250776,
"totalStakedEth": 9253766.831017949,
"proposalsMade": 304763,
"proposalsMissed": 536
},
"modules": [
{ "moduleId": 4, "total": 4567, "active": 4442, "slashed": 0 }
],
"indexer": {
"running": true,
"lastIndexedEpoch": 481915,
"currentEpoch": 481916,
"lag": 1,
"headKnown": true
},
"alerts": {
"critical": { "total": 292111, "last24h": 1012 },
"warning": { "total": 28186, "last24h": 1 },
"info": 817608
}
}Modules
GET /api/modules
The staking modules with their IDs, slugs, contract addresses and credentials type (wcType 1 is 0x01, 2 is 0x02).
curl -s 'https://app.roundbeat.com/api/modules'{
"network": "mainnet",
"modules": [
{
"id": 4,
"slug": "curated-v2",
"name": "Curated v2",
"wcType": 2,
"address": "0xda5f930ce326eb5205085d66c72a4e79d60cb8c1",
"indexed": true,
"activeValidators": 4442,
"balanceEth": 1916036.69,
"effectiveEth": 1915160
}
]
}Contract addresses
GET /api/network
The Lido contract addresses the Contracts page lists.
curl -s 'https://app.roundbeat.com/api/network'{
"network": "mainnet",
"contracts": {
"StakingRouter": "0xFdDf38947aFB03C621C71b06C9C70bce73f12999",
"…": "…"
},
"modules": [
{ "id": 4, "slug": "curated-v2", "name": "Curated v2", "address": "0xda5f930ce326eb5205085d66c72a4e79d60cb8c1", "withdrawalCredentialsType": 2 }
]
}Modules and operators
Operators of a module
GET /api/modules/{module}/summary
Every operator of one module with its validators and stake: the module pages’ tables. On 0x02 modules depositable is null and each row has an effective-balance histogram; Curated v1 rows carry their migration status.
curl -s 'https://app.roundbeat.com/api/modules/curated-v2/summary'{
"network": "mainnet",
"moduleId": 4,
"moduleSlug": "curated-v2",
"moduleName": "Curated v2",
"operators": [
{
"operatorId": 36,
"name": "ChainSafe - PGO",
"operatorType": "PGO",
"groupName": "ChainSafe",
"legacyOperatorId": 26,
"active": true,
"activeValidators": 135,
"exitingValidators": 0,
"totalExited": 0,
"balanceEth": 4326.16,
"effectiveEth": 4320,
"avgEffectiveEth": 32,
"validatorsAtMaxEB": 0,
"depositable": null,
"effectivenessEpochs": 223
}
]
}Operator effectiveness
GET /api/health/operators
Each operator’s effectiveness over the last 225 epochs (attestationRate, 0 to 1) and its proposals in the same window. state is active, no_active_validators or migrated. The module totals are at /api/health/summary.
| Parameter | Meaning |
|---|---|
module | The module (default Curated v1). |
curl -s 'https://app.roundbeat.com/api/health/operators?module=curated-v2'{
"network": "mainnet",
"moduleId": 4,
"windowEpochs": 225,
"operators": [
{
"operatorId": 36,
"name": "ChainSafe - PGO",
"state": "active",
"attestationRate": 0.9999,
"epochs": 223,
"proposalsMade": 0,
"proposalsMissed": 0,
"consecutiveMissed": 0,
"aum": { "validators": 135, "totalEth": 4326.16, "effectiveEth": 4320 }
}
]
}One operator
GET /api/operator/{module}/{id}/info
The operator page’s header. Note that the key counts here are strings. operator is null (with HTTP 200) for an unknown operator.
curl -s 'https://app.roundbeat.com/api/operator/curated-v2/36/info'{
"network": "mainnet",
"moduleId": 4,
"moduleName": "Curated v2",
"operatorId": 36,
"operator": {
"name": "ChainSafe - PGO",
"active": true,
"activeValidators": "135",
"totalDeposited": "135",
"totalExited": "0",
"exitingValidators": 0,
"aumEth": 4326.1602,
"effectiveEth": 4320,
"rewardAddress": "0x29d5a9917A82Dbb77e3362128C425d3a63eE8E6F",
"successorOf": { "moduleId": 1, "operatorId": 26, "name": "ChainSafe" }
}
}An operator’s validators
GET /api/indexed/operator/{id}/validators
The Validators tab. Balances are in gwei. display_status adds consolidating and consolidated for Curated v1 validators moving into Curated v2.
| Parameter | Meaning |
|---|---|
moduleId | The module. Pass it always. |
limit, offset | Page size (default 50, at most 500) and offset. |
status | Beacon status, for example active_ongoing; repeat or comma-separate for several. |
search | An index or pubkey. |
eb_min, eb_max | Effective balance range, in whole ETH. |
sort, dir | index, status, balance, effective_balance, activation_epoch or exit_epoch; asc (default) or desc. |
curl -s 'https://app.roundbeat.com/api/indexed/operator/36/validators?moduleId=4&limit=1'{
"total": 135,
"validators": [
{
"validator_index": 2367208,
"pubkey": "0x982b2eaf973c144dca8e26acddf3cb4258228cccaa19afbe88bedd40eede3ff5d3331b3d657d69e36d125912f95d18fd",
"status": "active_ongoing",
"display_status": "active_ongoing",
"balance": "32044339978",
"effective_balance": "32000000000",
"slashed": false,
"activation_epoch": "476509",
"exit_epoch": null
}
]
}An operator’s proposals
GET /api/indexed/operator/{id}/proposals
The Proposals tab: every proposal duty, proposed or missed, with its MEV. mev_status is one of the MEV classes. total counts the whole window, and time echoes it. A missed slot has no block, so its block fields are null.
| Parameter | Meaning |
|---|---|
moduleId | The module. Pass it always. |
time | A window, by slot; without it, every proposal on record. |
limit, offset | Default 50, at most 500. |
status | proposed or missed. |
relay | A relay name, or local for every proposed block with no relay (see Local in the tables). |
sort, dir | slot, epoch, validator, gas_used, txs or mev_reward_wei; desc by default. |
curl -s 'https://app.roundbeat.com/api/indexed/operator/36/proposals?moduleId=4&time=7d&limit=1'{
"total": 5,
"time": "7d",
"proposals": [
{
"slot": 15410402,
"epoch": 481575,
"validator_index": 2367350,
"proposed": true,
"fee_recipient": "0x388c818ca8b9251b393131c08a736a67ccb19297",
"gas_used": "27388941",
"transaction_count": 330,
"mev_status": "relayed",
"mev_reward_wei": "10424105614537579",
"relay_name": "ultrasound",
"relay_names": ["ultrasound", "aestus", "titan-global"],
"missed_best_bid_wei": null,
"timestamp_unix": "1791748847"
}
]
}An operator’s events
GET /api/indexed/operator/{id}/events
The operator’s event feed: the Events tab without its On-chain events panel, whose events are at …/contract-events and take no window.
| Parameter | Meaning |
|---|---|
moduleId | The module. Pass it always. |
time | A window, by the event’s epoch; without it, every event. |
limit, offset | Default 50, at most 500. |
type, exclude_type | Comma-separated event types without the eth. prefix, for example missed_proposal,likely_offline. |
curl -s 'https://app.roundbeat.com/api/indexed/operator/36/events?moduleId=4&type=upcoming_proposal&time=7d&limit=1'{
"total": 5,
"time": "7d",
"events": [
{
"id": 1119068,
"event_type": "upcoming_proposal",
"validator_index": 2367350,
"operator_id": 36,
"module_id": 4,
"epoch": "481575",
"created_at": "2026-10-11T19:54:50Z",
"details": { "slot": 15410402, "epochs_away": 1, "approx_minutes": 7, "operator_name": "ChainSafe - PGO" }
}
]
}Blocks and proposals
Proposal statistics
GET /api/blocks/stats
Block Analysis’s figures: success rate, relays and per-operator results. successRate is proposed blocks out of all proposal duties, to 4 decimals. mevRate is blocks that paid an MEV-Boost reward (mevBlocks) out of all proposed blocks in the window (successfulProposals), including blocks whose relay data is still pending or unknown; here 1,480 of 1,609. The operator page’s MEV-Boost rate is different: relayed out of relayed plus local blocks (MEV classes).
| Parameter | Meaning |
|---|---|
time | A window. |
module | Limit to one module. |
curl -s 'https://app.roundbeat.com/api/blocks/stats?time=24h'{
"network": "mainnet",
"time": "24h",
"totalProposals": 1614,
"successfulProposals": 1609,
"missedSlots": 5,
"successRate": 0.9969,
"mevBlocks": 1480,
"mevRate": 0.9198259788688626,
"relayedBlocks": 1480,
"builderBlocks": 0,
"localBlocks": 129,
"pendingBlocks": 0,
"unknownBlocks": 0,
"totalMevWei": "23303112100516462561",
"relayBreakdown": [{ "relay": "ultrasound", "count": 1274, "blockShare": 0.8608 }],
"byOperator": [{ "moduleId": 1, "operatorId": 31, "operatorName": "SenseiNode", "proposed": 61, "missed": 0, "successRate": 1 }]
}Blocks
GET /api/blocks
The Blocks table, newest first, across every Lido operator.
| Parameter | Meaning |
|---|---|
time, module | Window and module, as above. |
limit, offset | Default 50, at most 500. |
status, relay | proposed or missed; a relay name, or local for every proposed block with no relay. |
curl -s 'https://app.roundbeat.com/api/blocks?time=24h&limit=1'{
"network": "mainnet",
"total": 1614,
"blocks": [
{
"slot": 15421306,
"epoch": 481915,
"validatorIndex": 2223874,
"moduleId": 1,
"operatorId": 5,
"operatorName": "Blockscape",
"proposed": true,
"timestamp": "2026-10-13T08:21:35Z",
"executionBlockNumber": "26182339",
"mevStatus": "relayed",
"mevRewardWei": "5306657124144750",
"relayNames": ["titan-global"],
"missedBestBidWei": null
}
]
}One slot
GET /api/blocks/{slot}
The slot page. A slot more than 14,400 slots ahead (about two days) is a 404. /api/blocks/{slot}/missed-bids lists the relay bids for a locally built block.
curl -s 'https://app.roundbeat.com/api/blocks/15381999'{
"network": "mainnet",
"slot": 15381999,
"epoch": 480687,
"time": "2026-10-07T21:20:11Z",
"future": false,
"block": {
"operatorId": 36,
"moduleId": 4,
"operatorName": "ChainSafe - PGO",
"validatorIndex": 2369163,
"proposed": true,
"feeRecipient": "0x388c818ca8b9251b393131c08a736a67ccb19297",
"mevStatus": "relayed",
"mevRewardWei": "7683998740404956",
"relayNames": ["ultrasound", "aestus", "titan-global"],
"transactionCount": 249
},
"lidoPolicy": {
"vault": "0x388c818ca8b9251b393131c08a736a67ccb19297",
"feeRecipient": "0x388c818ca8b9251b393131c08a736a67ccb19297",
"feeRecipientOk": true,
"relayChecked": true,
"offListRelays": []
}
}Upcoming proposals
GET /api/blocks/upcoming
Lido proposals scheduled in the current and next epoch: the beacon chain does not publish proposers further ahead.
| Parameter | Meaning |
|---|---|
module | Limit to one module. |
curl -s 'https://app.roundbeat.com/api/blocks/upcoming?module=csm'{
"network": "mainnet",
"moduleId": 3,
"currentSlot": 15421336,
"currentEpoch": 481916,
"upcoming": [
{ "slot": 15421337, "epoch": "481916", "validatorIndex": 2281413, "moduleId": 3, "operatorId": 35, "operatorName": "CSM Operator 35", "secondsAway": 12, "minutesAway": 0 }
]
}Events
Event feed
GET /api/indexed/alerts
The feed behind app.roundbeat.com/alerts. category is the event type; source is beacon or contract (on-chain events, whose id is a string). The types and severities are those of the alert types, under their feed names. Its window counts events by when Roundbeat recorded them, while an operator’s events list counts them by epoch, so the two can differ slightly.
| Parameter | Meaning |
|---|---|
limit | Default 50, at most 500. |
before | Cursor for the next page: pass the previous response’s nextCursor. offset works up to 20,000. |
severity | critical, warning or info. |
time, module | Window and module. |
type | One event type, for example eth.missed_proposal. |
search | Matches the operator name. |
curl -s 'https://app.roundbeat.com/api/indexed/alerts?severity=critical&time=24h&limit=1'{
"network": "mainnet",
"total": 1012,
"hasMore": true,
"nextCursor": "1791877125658771.b.1140432",
"alerts": [
{
"id": 1140432,
"source": "beacon",
"severity": "critical",
"category": "eth.likely_offline",
"operatorId": 39,
"moduleId": 3,
"operatorName": "CSM Operator 39",
"validatorIndex": 1631660,
"epoch": "481907",
"timestamp": "2026-10-13T07:38:45Z",
"details": {
"consecutive_missed_epochs": 3,
"message": "Validator #1631660 missed attestations for 3 consecutive epochs (epoch 481907)"
}
}
]
}Sync committees
Lido sync committee members
GET /api/sync-committees
Lido validators in each sync committee period, by operator. The first period is the next one.
| Parameter | Meaning |
|---|---|
limit, offset | Periods per page (default 10, at most 50), newest first. |
module, search | Limit to one module, or to operators whose name matches. |
curl -s 'https://app.roundbeat.com/api/sync-committees?limit=1'{
"currentEpoch": 481915,
"currentPeriod": 1882,
"epochsPerPeriod": 256,
"totalPeriods": 175,
"syncCommittees": [
{
"period": 1883,
"startEpoch": 482048,
"endEpoch": 482304,
"isCurrent": false,
"totalMembers": 115,
"byOperator": [
{ "moduleId": 1, "operatorId": 0, "operatorName": "Staking Facilities", "validators": [343240] }
]
}
]
}Curated v2 migration
Migration progress
GET /api/lido/cmv2-migration
The Curated v1 to v2 migration for the whole module and per Curated v1 operator: consolidation counts by step (pending is requested but not queued yet), the operator’s stage (awaiting_pair, not_started, submitted, in_progress, done, exiting, left, inactive) and its Curated v2 targets with their share in basis points. This endpoint promises to only ever add fields.
curl -s 'https://app.roundbeat.com/api/lido/cmv2-migration'{
"network": "mainnet",
"updatedAt": "2026-10-13T08:27:49Z",
"totals": {
"legacyActive": 199453,
"total": 72505,
"pending": 0,
"queued": 13129,
"exited": 3283,
"completed": 56093,
"rejected": 0,
"ethMoved": 1794976,
"queueTailEpoch": 483710,
"completionRate": { "windowDays": 7, "completed": 16019, "perDay": 2288.43 }
},
"operators": [
{
"legacy": { "operatorId": 26, "name": "ChainSafe", "activeValidators": 7832, "exitingValidators": 0 },
"group": { "id": 32, "name": "ChainSafe" },
"status": "migrating",
"stage": "submitted",
"targets": [
{ "moduleId": 4, "operatorId": 36, "name": "ChainSafe - PGO", "operatorType": "PGO", "shareBp": 10000, "activeValidators": 135, "effectiveEth": 4320 }
],
"progress": { "pairsAllowed": 1, "submitted": 63, "total": 0, "requested": 0, "pending": 0, "queued": 0, "exited": 0, "completed": 0, "rejected": 0, "ethMoved": 0, "nextEtaEpoch": null }
}
]
}