# Public stats API 5 October 2026. Two JSON endpoints on the site for profitability sites, pool software and anyone who wants the network numbers without running a node: `/api/stats` and `/api/supply`. WhatToMine's listing form asks for an explorer or pool with an API, the reward halving schedule and a source to fetch total coins from; this is that source. A third endpoint, `/api/explorer`, feeds the explorer pages (docs/plans/explorer.md). Both are served by Vercel functions (`site/api/stats.mjs`, `site/api/supply.mjs`) that read what the devnet observer (`tools/observer/observer.mjs`) wrote to Neon; no secret is involved beyond the database connection the site already holds. Cached 10 s at the edge (`Cache-Control: public, max-age=10, s-maxage=10`), CORS open (`Access-Control-Allow-Origin: *`), GET only. A failed read answers 500 with `{ok: false, error}` and `Cache-Control: no-store`. The contract is the `FIELDS` list exported by each handler. `site/api/public-stats.test.mjs` checks a fixture against it without a database, and `tools/ci/public-api-check.mjs ` checks a deployment (CI runs it against https://igneum.network on master). ## /api/stats | Field | Meaning | Source | |---|---|---| | `network`, `chain_id`, `node_version` | Network name, EVM chain id (4461 mainnet, 4462 testnet, 4463 devnet, design 8.1), the node's version | observer `live_state` | | `algorithm` | The lottery hash, named | fixed text | | `stale`, `age_s`, `observer_updated_at` | `stale` when the observer has not written for 30 s; treat every number as last known then | observer | | `height` | The chain block number (the EVM block number): the number of the newest chain block the observer has a shard plan for | `live_blocks.number` | | `block_count`, `header_count` | Every DAG block the node holds | `getBlockDagInfo` | | `daa`, `blue_score` | DAA score and blue score of the newest block | `live_blocks`, `getSinkBlueScore` | | `difficulty` | The node's difficulty (target per block) | `getBlockDagInfo` | | `hashrate`, `hashrate_unit`, `hashrate_source` | H/s: the node's `estimateNetworkHashesPerSecond` over 1,000 blocks, else blue work added per second over 10 min | observer | | `block_time_target_s`, `block_time_measured_s` | 1 s by design (spec 2.1); 60 / DAG blocks in the last 60 s | observer | | `blocks_per_day_target`, `blocks_per_day_measured` | 86,400; the last hour's DAG blocks x 24 (null until the observer has an hour) | observer | | `block_reward` | `E(daa)` of spec 2.5 at the newest DAA score: `sompi` (8 decimals), `ign`, the 80% `miner_ign` and 20% `proving_pool_ign`, `ramp_factor`, `halving_period`, `next_halving_daa`, `next_halving_in_s` | `site/lib/emission.mjs` | | `last_block` | Hash, time, age, blue score, DAA, coinbase address, vote key id, EVM transaction count, whether it is a chain block | `live_blocks` | | `finality` | Finality v2: active, the latest locked checkpoint index and blue score | observer | | `peers`, `mempool`, `miners_10m` | Connected peers, mempool size, distinct vote keys in 10 min (a card runs several) | observer | Note for a profitability calculator: `block_reward` is per blue block merged; at the 1 block per second target that is also the reward per DAA second. The 20% proving-pool part is paid to provers, not to the miner of the block, so a miner's expected income per block is `miner_ign`. During the 30-day launch ramp the reward climbs from 10% to 100% of the schedule (`ramp_factor`); `/api/supply` shows where the ramp stands. Example, the devnet on 5 October 2026 (through the local preview against a test observer, so `block_time_measured_s` reflects a one-minute window): ``` { "ok": true, "now": "2026-10-05T19:32:09.321Z", "network": "igneum-devnet", "chain_id": 4463, "node_version": "2.1.0", "algorithm": "Igneum lottery hash: random-program GPU hash, new program every hour, generator v2 (docs/spec/01-lottery-hash.md)", "stale": false, "age_s": 0.9, "height": 82145, "block_count": 126358, "header_count": 126358, "daa": 126357, "blue_score": 123504, "difficulty": 125543017.00697394, "hashrate": 258756880, "hashrate_unit": "H/s", "hashrate_source": "the node's estimateNetworkHashesPerSecond over a 1,000-block window; blue work added per second over 10 min when the node refuses the window", "block_time_target_s": 1, "block_time_measured_s": 0.952, "blocks_per_day_target": 86400, "blocks_per_day_measured": 14040, "block_reward": { "sompi": "455909062", "ign": "4.55909062", "miner_ign": "3.6472725", "proving_pool_ign": "0.91181812", "split": "80% block producer, 20% proving pool", "daa_used": 126357, "ramp_factor": 0.143874, "halving_period": 0, "next_halving_daa": 63115200, "next_halving_in_s": 62988843 }, "last_block": { "hash": "bbec3139d3f38e3517716374707998e77f536a67813edfb619c5bed93a5779ab", "time": "2026-10-05T19:32:06.157Z", "ts_ms": 1791228726157, "age_s": 3.2, "blue_score": 123504, "daa": 126357, "miner": "igneumdev:qrt8nzgrghr2a2xuc7lstzclcnt3n632d2chhc946rphkc6flcyswvkrym8s4", "miner_id": "7b8ef6fd", "tx_count": 0, "chain": true }, "finality": { "active": true, "latest_locked_index": 4116, "latest_locked_blue_score": 123480, "chain_id": "igneum-devnet" }, "peers": 4, "mempool": 0, "miners_10m": 21, "observer_updated_at": "2026-10-05T19:32:08.394726+00:00", "source": "tools/observer reading one node every 2 s; reward from docs/spec/02-consensus.md 2.5 at the node's DAA score" } ``` ## /api/supply | Field | Meaning | |---|---| | `unit` | IGN; the coinbase pays in 8-decimal units (open item O-2.6), the EVM shows 18 | | `daa` | The newest DAA score the observer stored | | `max_supply_ign` | 4,000,000,000, the hard cap (spec 2.5, no tail emission: spec 5.10) | | `circulating_ign`, `circulating_sompi` | Minted so far by the rule: `E(t)` summed over every DAA second from 0 to `daa`, exact (floor sum, `mintedByRule`) | | `minted_at_end_ign`, `never_minted_ign` | What the schedule reaches when the per-second rate hits 0 (period 32), and the part of the cap the ramp and the floors never mint | | `emission_per_second_ign`, `block_reward_ign` | `E(daa)` now | | `halving` | Interval 63,115,200 DAA s (two years), current period, the next halving's DAA score, seconds to it, a date estimate at one DAA second per second | | `ramp` | 10% at genesis to 100% at DAA 2,592,000 (30 days), the factor now, whether it is complete | | `schedule` | 33 rows: period, start and end DAA, years from genesis, IGN per second, IGN per block at 1 BPS, minted by the end of the period, share of the cap | | `check` | The observer's hourly comparison of the chain against the rule over its newest 500 blocks: `rule_match` counts blocks whose coinbase payload declares exactly `E(daa)`; `sum_match` counts blocks whose coinbase outputs equal the declared subsidies of the blocks they merge; `examples` names mismatches | | `rule`, `source`, `note` | The formula, where it lives, and the caveat: the chain pays per block merged, so a block rate above target mints above the schedule for as long as it lasts | Example (schedule cut to five rows here): ``` { "ok": true, "now": "2026-10-05T19:32:09.374Z", "network": "igneum-devnet", "chain_id": 4463, "unit": { "symbol": "IGN", "decimals_consensus": 8, "decimals_evm": 18, "note": "the coinbase pays in 8-decimal units (open item O-2.6 keeps Kaspa's SOMPI_PER_KASPA); the EVM shows the same amount at 18 decimals" }, "daa": 126357, "max_supply_ign": "4000000000", "circulating_ign": "488236.39686436", "circulating_sompi": "48823639686436", "minted_at_end_ign": "3963038988.86765648", "never_minted_ign": "36961011.13234352", "emission_per_second_ign": "4.55909062", "block_reward_ign": "4.55909062", "halving": { "interval_daa_s": 63115200, "interval_years": 2, "period": 0, "next_halving_daa": 63115200, "next_halving_in_s": 62988843, "next_halving_estimate": "2028-10-03T20:26:12.374Z", "estimate_note": "the estimate assumes one DAA second per wall-clock second from now" }, "ramp": { "start_percent": 10, "length_daa_s": 2592000, "length_days": 30, "factor_now": 0.143874, "complete": false, "remaining_s": 2465643, "withheld_ign": "36961011.13234352", "withheld_note": "the ramp withholds about 37 million IGN that are never minted; integer floors withhold the rest (spec 2.5)" }, "schedule": [ { "period": 0, "start_daa": 0, "end_daa": 63115200, "years_from_genesis": "0 to 2", "per_second_ign": "31.68808781", "per_block_ign_at_1bps": "31.68808781", "minted_by_end_ign": "1963038999.85152848", "share_of_cap_by_end": 49.0759 }, { "period": 1, "start_daa": 63115200, "end_daa": 126230400, "years_from_genesis": "2 to 4", "per_second_ign": "15.8440439", "per_block_ign_at_1bps": "15.8440439", "minted_by_end_ign": "2963038999.40880848", "share_of_cap_by_end": 74.0759 }, { "period": 2, "start_daa": 126230400, "end_daa": 189345600, "years_from_genesis": "4 to 6", "per_second_ign": "7.92202195", "per_block_ign_at_1bps": "7.92202195", "minted_by_end_ign": "3463038999.18744848", "share_of_cap_by_end": 86.5759 }, "... 29 more rows ...", { "period": 32, "start_daa": 2019686400, "end_daa": 2082801600, "years_from_genesis": "64 to 66", "per_second_ign": "0", "per_block_ign_at_1bps": "0", "minted_by_end_ign": "3963038988.86765648", "share_of_cap_by_end": 99.0759 } ], "check": { "bps": 1, "sampled": 470, "examples": [], "sum_match": 466, "checked_at": "2026-10-05T19:30:28.385Z", "rule_match": 470, "sum_skipped": 4, "sum_mismatch": 0, "rule_mismatch": 0 }, "rule": "E(t) = ramp(t) * floor(10^9 * UNIT / 31,557,600) >> floor(t / 63,115,200); ramp(t) = min(1, 1/10 + 9/10 * t / 2,592,000); t = DAA score / bps, bps = 1", "source": "docs/spec/02-consensus.md 2.5; vendor/igneum-node consensus/core/src/igneum.rs block_subsidy and launch_ramp; circulating = the rule summed over every DAA second from 0 to the node's DAA score (site/lib/emission.mjs mintedByRule, exact)", "note": "circulating is the schedule at this DAA score. The chain pays E per blue block it merges and per red inside the DAA window, which tracks the schedule one block per DAA step; the devnet of 3 October 2026 ran 4.7x the schedule for eight minutes during a retarget lag (spec 2.5). check reports what the observer measured on the newest blocks." } ``` ## /api/explorer The explorer's own feed, cached 5 s: `?blocks=N[&before=ms]` (latest blocks), `?block=hash`, `?height=N`, `?address=0x..|igneumdev:..`, `?search=q`. Shapes are in `site/api/explorer.mjs`; the pages are the reference client. Balances need `EXPLORER_EVM_RPC` on the deployment (a public EVM JSON-RPC); without it `balance.available` is false with the reason.