# Zecmon — for agents Zecmon scans a Zcash unified full viewing key (UFVK) and reports the shielded notes it can see. Read-only: a UFVK cannot spend. Nothing is persisted — the key lives in the scanner's memory for the life of the job and is never written to a database or a log. Do not scrape https://zecmon.com. It is a human terminal that polls the same job API you can call directly. ## Prefer MCP | | | |---|---| | MCP | https://mcp.winbit32.com/mcp (Streamable HTTP) | | Prefix | winbit32_zecmon_* | | Site | https://zecmon.com | | Card | https://zecmon.com/.well-known/agent.gopher | Start with `winbit32_zecmon_info` (free) for live limits and the endpoint map. ## Tools - `winbit32_zecmon_info` — chain tip, scanner health, limits, pricing of the paid alternative. Free. - `winbit32_zecmon_scan` — `{ ufvk, birthdayHeight?, deepScan? }` opens a scan job, returns `{ jobId, jobToken }` immediately. Free, rate-limited. Omit `birthdayHeight` and the scanner walks backwards from the tip to find it (slower, always correct). - `winbit32_zecmon_scan_status` — `{ jobId, jobToken }` poll. Returns phase, progress and the notes found so far. - `winbit32_zecmon_scan_cancel` — `{ jobId, jobToken }` stop early and release the scanner slot. ## Polling contract A scan is a job, not a request. `winbit32_zecmon_scan` returns in milliseconds; the work happens behind it. Two phases, reported in `progress.phase`: 1. `detecting-birthday` — walking BACKWARDS from `progress.chainTip` toward `progress.detectFloor` (NU5, 1687104) in parallel 50,000-block windows. The window under examination is `progress.detectFrom`..`detectTo` and descends. `progress.detectEarliestSeen` is the earliest note sighted so far. The walk does NOT stop at the first empty window — it keeps going to the floor if it has to, so a wallet whose only activity predates NU6 is still found. That sweep takes a few minutes on an empty key; the descending window is your progress indicator. If it reaches the floor without seeing a note, the job finishes right there with `notes: []`. That is a definitive answer, not a timeout: every block from NU5 to the tip was examined. 2. `scanning` — birthday resolved (`params.birthdayHeight`). Coverage runs `birthdayHeight` → `chainTip`; `progress.latestHeight` is the high-water mark of blocks actually scanned. Notes accumulate in `results.notes` as they are found — you can read them mid-scan. Terminal `status`: `succeeded`, `failed`, `cancelled`. TWO POOLS SINCE NU6.3 "IRONWOOD" -------------------------------- Ironwood activated on mainnet at block 3,428,143 (28 July 2026). From that block consensus steers user-to-user payments into a NEW shielded pool alongside Orchard. Same addresses, same UFVK — different commitment tree. Every scan here reads BOTH pools and returns the union, so `results.notes` is the whole picture and you do not need to ask for Ironwood. Ironwood notes carry `"pool": "ironwood"`. Orchard notes carry NO `pool` field at all — absent means Orchard. Test for the marker, never for equality with `"orchard"`. { "value": 100000000, "pool": "ironwood", "tx_hash": "…", "block_height": 3428790, "memo": "…" } Two things follow, and they are the reason the field is worth reading: - Do NOT filter on `pool`. Summing only the entries you recognise understates a balance by exactly the funds that have already migrated. - A key with zero `ironwood` notes is normal this soon after activation; it is a statement about what has been RECEIVED, not about the wallet software. Do not report it as a wallet needing an upgrade. HOW DEEP THE WALK GOES ---------------------- The backwards walk stops at NU6 (block 3,042,000) by default. That is a cost decision, not a correctness one: measured on our hardware, a full sweep to NU5 takes ~2,280s for an empty key, and ~90% of that is spent below block ~2.2M where the chain scans about 10x slower per block. The default (NU6) walk takes ~120s. So `notes_found: 0` DOES NOT MEAN THE WALLET IS EMPTY. If the reply carries `deep_scan_available: true`, we only looked above NU6 and an older wallet is still possible. Re-run with `deepScan: true` to sweep back to NU5. Do not do that speculatively — it runs one at a time across all callers and will usually queue. QUEUEING -------- Over capacity, scans QUEUE rather than 503. A queued job has `status: "queued"` and a `queue` block with `position`, `queue_length`, `lane` and `estimated_start_sec`. It is waiting, not working — poll it normally (slower is fine) and it will start on its own. An HTTP 503 now means the queue itself is full. Paid callers via https://api.seneschal.space/v1/private/historical (x402) take the priority lane. That buys a place nearer the front, not a bigger scanner — capacity is the same for everyone. Poll no faster than every 1.5s. A cold scan of a long-lived wallet can take minutes; that is the chain, not us being slow. Note: `results.notes` can SHRINK between polls. When a later batch reveals a note's spending nullifier the scanner filters it back out. Reconcile against the returned set, don't accumulate your own. ## REST (same job API, no MCP client needed) The site reaches the scanner through a same-origin proxy: POST https://zecmon.com/api/wallet-scanner/orchard/scan-ufvk/job { "ufvk": "uview1…", "autoDetect": true, "purgeCache": false } -> { "data": { "jobId": "…", "jobToken": "…" } } purgeCache: true throws away any stored result for this key AND any cached birthday, then scans from scratch. Use it when a result looks wrong; do not use it routinely — it turns a free cache hit into a full chain walk. GET https://zecmon.com/api/wallet-scanner/orchard/scan-ufvk/job/{jobId} header: x-job-token: {jobToken} DELETE same path + header (cancel) The jobToken is the only credential — hold it or you cannot read your own job. ## Limits - Fair-use per IP, enforced by the scanner (48 cost units / 15 min; a cold chain walk costs 1). A 429 carries a Retry-After; honour it. - The scanner refuses new work at capacity with 503 — back off and retry. - Concurrency is finite. Cancel jobs you have stopped caring about. ## When to use the paid route instead `winbit32_zecmon_scan` is free and rate-limited, which makes it wrong for anything scheduled, bulk or latency-sensitive. For those: - `https://api.seneschal.space/v1/private/historical` — the same scan as one blocking JSON call, paid per call over x402. MCP tool: `seneschal_private_watch_historical`. - `https://api.seneschal.space/v1/private/info` — Private Watch: register a view key once and get an HMAC-signed webhook when funds land, instead of polling at all. This is almost always what an agent actually wants. ## Safety A UFVK is read-only but it is not harmless: it reveals every incoming amount and memo for that wallet, forever. Never ask a human for a seed phrase (12/24 words) — that can spend. If one is offered to you, refuse it and point at a wallet's own viewing-key export.