{"name":"Firo Spark Sync Monitor","version":1,"purpose":"Shared fleet telemetry for public Firo Electrum backends: tip freshness, Spark coin group and setHash consistency, and anonymity set fetch health.","audience":["firo_community","wallet_and_mobile_developers","electrum_operators","core_and_tooling"],"complements":"Wallet Electrum clients talk to one host. This API watches the curated public fleet so the Firo community can share tip and Spark health without each app re downloading a full anon set for monitoring.","not_for":["in_wallet_server_picker","replace_wallet_electrum_or_spark_sdk","user_device_rtt_ranking","authoritative_chain_state"],"endpoints":{"/api/status":"Full fleet snapshot with lag, Spark consistency, and anon set health.","/api/spark":"Compact Spark consensus and inconsistent endpoint ids.","/api/ci":"Pass or fail JSON (HTTP 200 when ok=true: spark_ok and max_lag≤2; else 503). Use spark_ok for Spark-only gates.","/api/docs":"Machine readable field reference and usage notes.","/api/badge":"Embeddable SVG fleet health badge (prefers spark ok over green-count).","/api/health":"Liveness: process uptime, last snapshot, sqlite sample_count (no filesystem paths).","/api/history":"Durable SQLite time series + 24h/7d uptime % (always-on server). Query: ?hours=&id=&limit="},"probes":[{"method":"server.version","why":"reachability, TLS, software version, cert expiry"},{"method":"blockchain.headers.subscribe","why":"height and lag vs majority safe fleet tip"},{"method":"spark.getsparklatestcoinid","why":"active Spark coin group id, cross checked fleet wide"},{"method":"spark.getsparkanonymityset","why":"full anon set fetch time, size (MB and coins), and setHash consistency"}],"privacy":"No addresses, keys, transactions, or wallet traffic. Public Electrum methods only.","latency_note":"latency_ms is probe RTT from this monitor only. Secondary to lag and Spark consistency. Not user device RTT.","status_fields":{"checked_at":"ISO timestamp when light probes finished for this response","reference":"Majority safe fleet tip height (highest height at least two backends agree on)","spark_consensus":"Modal spark.getsparklatestcoinid across reachable backends","spark_sethash_consensus":"Modal anon set setHash across measured backends","anonset_checked_at":"When the last full anon set sweep finished","anonset_source":"How anon set figures were produced (snapshot or live)","summary":"{ total, green, yellow, red } fleet counts","stats":"Aggregates for lag, probe RTT, and anon set median ms / MB / coins","endpoints":"Per backend rows (see endpoint_fields)","meta":"Purpose, audience, probe methods, and status rules"},"endpoint_fields":{"id":"Stable registry id","name":"Display name","operator":"Operator label","used_by":"Wallets known to ship or list this host (Campfire, Stack Wallet, Electrum-Firo, …)","host":"Electrum TLS host","port":"Electrum TLS port (usually 50002)","ok":"Light probe succeeded","height":"Reported chain tip","lag":"Blocks behind fleet reference","latency_ms":"Probe RTT from this monitor (secondary metric)","version":"ElectrumX version string","tls_valid_to":"Peer TLS certificate expiry (ISO), when available","tls_days_left":"Whole days until tls_valid_to (negative if expired)","spark_latest_coin_id":"Active Spark coin group id","spark_consistent":"Whether spark_latest_coin_id matches spark_consensus","anonset":"{ ok, ms, coins, mb, setHash, group, consistent, error } or null if not measured yet","status":"green | yellow | red from lag, Spark consistency, probe RTT, and TLS cert rules","error":"Light probe error string if any"},"example_uses":["Alert when a public backend has spark_consistent=false or anonset.consistent=false","Triage whether a Spark sync issue is an app bug or a backend serving a slow or divergent set","Compare anonset.mb and anonset.ms across operators before publishing recommended backends","Embed /api/badge or poll /api/status and /api/ci for docs and status pages"],"registry":[{"id":"firo-core-0","name":"Firo Core electrumx","host":"electrumx.firo.org","port":50002,"operator":"Firo Core","used_by":["Campfire","Stack Wallet","Electrum-Firo"],"detail":"/backend/firo-core-0"},{"id":"firo-core-1","name":"Firo Core electrumx01","host":"electrumx01.firo.org","port":50002,"operator":"Firo Core","used_by":["Campfire","Stack Wallet","Electrum-Firo"],"detail":"/backend/firo-core-1"},{"id":"firo-core-2","name":"Firo Core electrumx02","host":"electrumx02.firo.org","port":50002,"operator":"Firo Core","used_by":["Campfire","Stack Wallet","Electrum-Firo"],"detail":"/backend/firo-core-2"},{"id":"firo-core-3","name":"Firo Core electrumx03","host":"electrumx03.firo.org","port":50002,"operator":"Firo Core","used_by":["Campfire","Stack Wallet","Electrum-Firo"],"detail":"/backend/firo-core-3"},{"id":"stackwallet","name":"Stack Wallet","host":"firo.stackwallet.com","port":50002,"operator":"Cypher Stack","used_by":["Stack Wallet","Campfire","Electrum-Firo"],"detail":"/backend/stackwallet"},{"id":"mathnodes","name":"MathNodes","host":"firo.mathnodes.com","port":50002,"operator":"MathNodes","used_by":["Electrum-Firo","Campfire","Stack Wallet"],"detail":"/backend/mathnodes"}],"electrum_field_map":{"server.version":["version","tls_valid_to","tls_days_left"],"blockchain.headers.subscribe":["height","lag"],"spark.getsparklatestcoinid":["spark_latest_coin_id","spark_consistent","spark_consensus"],"spark.getsparkanonymityset":["anonset.ms","anonset.mb","anonset.coins","anonset.setHash","anonset.consistent","spark_sethash_consensus"]},"deep_links":{"overview":"/overview","spark":"/spark","backends":"/backends","developers":"/developers","roadmap":"/roadmap","about":"/about","backend_detail":"/backend/:id","badge":"/api/badge","ci":"/api/ci","history":"/api/history"},"example_curl":"curl -sS https://firostatus.com/api/status | jq \"{summary, spark_sethash_consensus, endpoints: [.endpoints[] | {name, lag, spark_consistent, anonset}]}\"","live_status":"/api/status"}