Answer first
A free, open Zcash data API
The ZecStats API is the same deterministic pipeline that renders zecstats.org, exposed as public read-only endpoints. One request to /api/zec/summary returns the entire dashboard — shielded pool balances, the Ironwood migration, shield/deshield flows, supply, halving, price, network health and cross-chain ZEC volume — as a single JSON document, and bulk history downloads as CSV. It is free, it needs no API key, and it is licensed CC BY 4.0 with attribution to zecstats.org.
Free, no key, no signup
No token, no account, no quota form. Issue a GET and you have the data — the same bytes the site itself renders from.
Callable from a browser
The public read surface sends Access-Control-Allow-Origin: * on GET and HEAD and answers preflight, so a page on any domain can read it directly.
JSON for live, CSV for history
Live state comes from /api/zec/summary; daily history downloads as CSV — see the data downloads page.
Provenance on every metric
Each section carries {source, fetchedAt, ok, stale}, so staleness is something your code detects rather than something you have to trust.
Reference
Every endpoint
Everything below is a GET, read-only, and open to any origin. Paths are relative to https://zecstats.org. Timestamps are ISO-8601 UTC, ZEC amounts are ZEC (not zatoshi) as JSON numbers, and any value that could not be observed is null.
Live JSON
GET /api/zec/summary
Params: none.
Returns: the whole dashboard as one JSON document — price, network, supply, pools, ironwood, flows, halving, crossChain, mempool, recentBlocks, recentPoolDeltas, plus sources, warnings and diagnostics.
Cache: public, max-age=45, stale-while-revalidate=120
Start here — everything the site renders comes from this one document.
GET /api/zec/price-history
Params: window=24h|7d|1m|3m|ytd|1y|all (default 7d).
Returns: OHLC candles from the app-owned price store: points[] of {t,o,h,l,c} plus granularity (5m for 24h, 30m for 7d, 1d for 1m–1y, 1w for all), pointCount, rangeStart, rangeEnd, performancePct, highUsd, lowUsd, currentPriceUsd, generatedAt, warning.
Cache: max-age=60, stale-while-revalidate=120 for 24h/7d; max-age=300, stale-while-revalidate=900 for the longer windows.
GET /api/zec/price-comparison
Params: window=7d|1m|3m|ytd|1y|all (default 1m) and assets= — a comma-separated list drawn from zec, bitcoin, ethereum: two or three unique assets, and zec must be one of them (default: all three).
Returns: one normalized series per asset (basis: "normalized-percent", source: "binance-vision") with startPriceUsd, currentPriceUsd, performancePct and points[]. An invalid query returns HTTP 400.
Cache: public, max-age=300, stale-while-revalidate=900
GET /api/search
Params: q — the query string, up to 200 characters (an empty q returns the zero state).
Returns: the deterministic answer engine's response: intent, interpretation chips, a cited answer (headline, value, facts, sources, coverage, asOf) when the query resolves, grouped results, didYouMean, suggestions, tookMs, warning.
Cache: public, max-age=10, stale-while-revalidate=30
Rate limited to 600 requests per minute across all callers; over that it returns HTTP 429.
GET /api/share/manifest.json
Params: none.
Returns: every share surface on the site: app, url, generatedAt, count, and items[] with key, title, description, shareUrl, linkUrl, imageUrl, pngDownloadUrl, downloadUrl, shareIntentUrl, xIntentUrl and tweetText.
Cache: public, max-age=60
Bulk CSV
All three CSV endpoints return text/csv; charset=utf-8 with Content-Disposition: attachment, Cache-Control: public, max-age=3600 and an X-License: CC-BY-4.0 header. from and to are inclusive UTC calendar days; a malformed value is ignored rather than rejected. An empty cell means the value was not observed — never zero. Coverage, column semantics and caveats live on the downloads page.
GET /api/zec/pools.csv
Params: optional from=YYYY-MM-DD and to=YYYY-MM-DD.
Returns: daily pool balances — day,height,transparent,sprout,sapling,orchard,ironwood,lockbox,chain_supply. One row per UTC day (the last observation of that day) from the ZecStats snapshot store. Amounts are ZEC.
Cache: public, max-age=3600; served as text/csv; charset=utf-8 with Content-Disposition: attachment.
GET /api/zec/flows.csv
Params: optional from=YYYY-MM-DD and to=YYYY-MM-DD.
Returns: daily shield/deshield flows — day,shield_zec,deshield_zec,net_zec,shield_tx,deshield_tx, one row per UTC day. Amounts are ZEC; the _tx columns are transaction counts.
Cache: public, max-age=3600; text/csv; charset=utf-8, Content-Disposition: attachment.
GET /api/zec/price.csv
Params: optional token=zec|bitcoin|ethereum (default zec), from=YYYY-MM-DD and to=YYYY-MM-DD.
Returns: daily OHLC — day,open,high,low,close,volume,market_cap_usd, one row per UTC day.
Cache: public, max-age=3600; text/csv; charset=utf-8, Content-Disposition: attachment.
Cards & charts
GET /api/share-card.svg · .png
Params: none.
Returns: the main ZecStats KPI card (1200×630), rendered server-side from the live summary. The SVG is the source of truth; the PNG is rasterized from it.
Cache: public, max-age=60
GET /api/chart/<kind>.svg · .png
Params: <kind> is one of summary (alias summary-v2), shielded, ironwood, flows, halving, price, price-ath, price-performance.
Returns: a 1200×630 card for that topic, generated from the current data with no client-side JavaScript — safe to hotlink in a post, a README or an embed.
Cache: public, max-age=60 (price-ath.svg uses max-age=300).
Health
GET /health
Params: none.
Returns: { ok, service, timestamp } — a liveness probe. It does not touch the data pipeline.
Cache: no cache headers set.
GET /health/ready
Params: none.
Returns: { ok, service, cache: { cached, expiresAt, generatedAt } } — readiness plus the age of the summary currently being served.
Cache: no cache headers set.
cache.generatedAt is the cheapest way to check freshness before pulling the full summary.
Two further machine-readable surfaces are worth knowing about: /llms.txt, a plain-text guide to the site for AI agents (cached an hour), and /sitemap.xml (cached five minutes).
Not part of the public API: /api/feedback, /api/events and /api/admin/* are same-origin only — they receive no CORS headers, and the admin routes are cloaked as 404 without a token. /api/zec/refresh is not a public data endpoint either: its GET form only echoes the summary that is already cached, and its POST form — which spends our rate-limited upstream budget — is admin-gated.
Schema
What /api/zec/summary returns
Thirteen top-level keys. Pool and supply values are ZEC as floating-point numbers, USD values are plain numbers, and every timestamp is ISO-8601 UTC.
generatedAt
ISO-8601 UTC timestamp of the snapshot that every other field in the document belongs to.
price
usd, change24hPct, btc, marketCapUsd, marketCapRank.
network
height, blocks24h, tx24h, difficulty, hashrate (the source's own string) and hashrateRaw, peers, nodes, mempoolCount, avgBlockTimeSeconds, subversion, chainSizeGb.
supply
total (consensus chain supply), max (21,000,000), pctIssued, inflationAnnualPct, emissionPerDayZec.
pools
Balances for transparent, sprout, sapling, orchard, ironwood and lockbox, plus shieldedTotal, shieldedPct, shieldedUsd, updatedAt and deltas — 1/7/30-day changes (d1, d7, d30) for sprout, sapling, orchard, ironwood and the shielded total.
ironwood
The NU6.3 migration: ironwoodZec, orchardRemainingZec, migrationPct, orchardMigrated24hZec, ironwoodInflow24hZec, orchardAtActivationZec, totalInflowZec, spentOutZec, inflowBySource (orchard / sapling / transparent / other), activationHeight, activationDate.
flows
daily[] and hourly[] points of {date, shield, deshield, net, shieldTx, deshieldTx}, the last24h totals, and recentTxs[] — individual boundary transactions (shield, deshield or fully_shielded; the amount is null for fully-shielded transactions, because the chain does not reveal it).
halving
block, blocksRemaining, estimatedDate, currentSubsidy, nextSubsidy, and the subsidy split: minerSharePct, zcgSharePct, lockboxSharePct.
crossChain
intents (24h volume, swap count, inflow/outflow USD, a daily[] trend series and recent[] swaps), maya (24h volume, ZEC pool depth, status), and totalVolume24hUsd.
mempool
count plus recent[] unconfirmed transactions with their sapling, orchard and ironwood action counts.
recentBlocks · recentPoolDeltas
Newest blocks (height, hash, timestampMs, txCount, sizeBytes, fees) and observed pool movements between two indexer snapshots (fromHeight → toHeight, per-pool deltas, shieldedDelta).
sources · warnings · diagnostics
sources maps a section id (price, pools, network, nodes, halving, turnstile, flows, poolDeltas, crossChain) to {source, fetchedAt, ok, stale, note?}. warnings[] is written for humans; diagnostics[] is ops telemetry.
Copy-paste
Working examples
Fetch the whole summary from a shell:
curl -sS "https://zecstats.org/api/zec/summary" -H "Accept: application/json"
Read it from a browser page on any domain — this works because the public API now sends permissive CORS headers on GET:
const res = await fetch("https://zecstats.org/api/zec/summary");
const s = await res.json();
console.log(`${s.pools.shieldedTotal} ZEC shielded (${s.pools.shieldedPct}% of supply)`);
console.log(`Ironwood migration: ${s.ironwood.migrationPct}%`);
// Provenance: was the pools section read live, or served from a cache?
const { source, fetchedAt, ok, stale } = s.sources.pools;
if (!ok || stale) console.warn(`pools data is ${stale ? "stale" : "unavailable"} (${source}, ${fetchedAt})`);
// Anything user-facing is worth repeating in your own UI:
s.warnings.forEach((w) => console.warn(w));
Pull the shielded percentage with jq:
# just the number
curl -s https://zecstats.org/api/zec/summary | jq '.pools.shieldedPct'
# a one-line report, with a staleness check
curl -s https://zecstats.org/api/zec/summary \
| jq -r '"\(.pools.shieldedPct)% of ZEC is shielded (\(.pools.shieldedTotal) ZEC) as of \(.generatedAt)"
+ (if .sources.pools.stale then " [STALE]" else "" end)'
Grab a slice of daily history as CSV:
curl -s "https://zecstats.org/api/zec/pools.csv?from=2026-07-30" -o zcash-pools.csv
curl -s "https://zecstats.org/api/zec/flows.csv?from=2026-06-29&to=2026-08-01" -o zcash-flows.csv
curl -s "https://zecstats.org/api/zec/price.csv?token=zec&from=2019-03-21" -o zec-price.csv
Differentiator
Provenance is an API feature
Most data APIs hand you a number and let you assume it is current. This one hands you the number and the receipt — that is the part worth building on. Expand any card for the detail.
Every section carries a source stamp you can read programmatically.
Why / details
summary.sources maps each section to {source, fetchedAt, ok, stale, note?}. source names the upstream that produced the value (for example cipherscan, blockchair, emission-math, zodl-indexer, or zecstats-db when it came from our own store), fetchedAt is when it was retrieved, ok says whether that fetch succeeded, and stale says whether the value came from a last-good cache instead of a live read.
That makes staleness a machine-readable fact rather than something you have to infer. Most crypto data APIs silently carry a stale value forward and give you no way to tell.
Unavailable means null. It never means zero, and it is never a guess.
Why / details
When a source fails and nothing trustworthy is cached, the field is null — the site renders that as “—”. Nothing in this pipeline interpolates, extrapolates, or rounds a missing measurement into a plausible-looking number.
Supply gets an extra gate: a chain supply outside the consensus emission envelope is withheld rather than published. Treat null as “not observed”, never as 0.
warnings[] is for your users; diagnostics[] is for operators.
Why / details
warnings holds user-facing degradations in plain English — the same strings the dashboard shows in its notice strip. If you surface ZecStats data in your own UI, rendering these is the single highest-value thing you can do with the response.
diagnostics is ops telemetry: cross-check disagreements, withheld-value guards, upstream-quality notes. It is consumed by our audit harness and patrol jobs, and is not meant for display.
You can detect a stale response in one line of code.
Why / details
Compare generatedAt against your own clock, or read the specific section you depend on:
const s = await (await fetch("https://zecstats.org/api/zec/summary")).json();
const poolsAreLive = s.sources.pools.ok && !s.sources.pools.stale;
Because unavailable data is null rather than a stale carry-forward, a consumer that checks these two things can never accidentally present a 2022 number as today's.
Fair use
Rate limits and polite polling
There is no API key, no auth and no per-consumer quota. The only limits enforced in the app are these:
| Endpoint | Enforced limit |
|---|---|
| /api/search | 600 requests/minute, global (HTTP 429 above that) |
| /api/zec/summary and every other read endpoint | no hard limit — fair use |
| /api/feedback (not part of this API) | 20 submissions/minute, global |
| /api/events (not part of this API) | 1,200/minute global · 120/minute per client |
The fair-use ask: the pipeline refreshes roughly every two minutes, and /api/zec/summary is cached with max-age=45, stale-while-revalidate=120 — polling faster than about once a minute returns you the same bytes and only costs us bandwidth. Cache what you fetch, respect the Cache-Control headers we send, back off on HTTP 429, and send a user agent that identifies your project so we can reach you if something you depend on is about to change.
Licence
Attribution & licence
ZecStats data — JSON, CSV and cards alike — is published under the Creative Commons Attribution 4.0 International licence (CC BY 4.0). You may use, reshape, redistribute and build commercial products on it, as long as you credit the source. Copy this line:
Data: ZecStats (https://zecstats.org), CC BY 4.0
In HTML:
<a href="https://zecstats.org">Data: ZecStats</a> — CC BY 4.0
A visible link back matters more than the legal formality: it lets your readers verify the number, and it is the only thing we get in return. If you are publishing charts or a paper, the downloads page carries a suggested citation. If you build something on this API we would like to hear about it — use the feedback button on any page, and see about ZecStats for who is behind it.
Questions
API FAQ
Is the ZecStats API free?
Yes. Every endpoint on this page is free, public and read-only. There is no paid tier, no signup and no commercial licence to negotiate — the data is published under CC BY 4.0, and all we ask for is attribution to zecstats.org.
Do I need an API key?
No. There is no API key, no token and no authentication of any kind on the read endpoints — just issue a GET. The write endpoints (feedback and analytics events) and the admin endpoints are not part of the public API and are not reachable cross-origin.
Can I use this from a browser?
Yes. The public read-only surface sends Access-Control-Allow-Origin: * on GET and HEAD for /api/* and /health*, and answers preflight requests, so a page on any domain can fetch ZecStats data directly. Feedback, events and admin endpoints stay same-origin.
How often does the data update?
The pipeline refreshes roughly every two minutes, and /api/zec/summary is cached for 45 seconds with a 120-second stale-while-revalidate window, so polling faster than about once a minute returns the same bytes. The snapshot behind this page was generated at 2026-08-06 16:54 UTC.
Can I use ZecStats data in my own project?
Yes — in wallets, dashboards, research papers, newsletters, bots and AI agents, commercially or not, under CC BY 4.0. Credit ZecStats and link back to zecstats.org so your readers can check the numbers themselves.
How do I know if a number is stale?
Read the sources block. Every section of the summary carries {source, fetchedAt, ok, stale} — if stale is true, the value came from a last-good cache rather than a live fetch, and warnings[] usually explains why. Values that could not be obtained at all are null, never a carried-forward guess.
What happens when a source is down?
The pipeline walks a ladder: primary source, then an independent fallback, then the last-good snapshot (served with a stale stamp and a warning), and finally null. It never fabricates a value to fill the gap — the methodology page lists the per-metric primaries, fallbacks and cross-checks.