Seneschal Data API
Pay-per-call data over HTTP and the Model Context Protocol. The headline product is Private Watch — view-key payment webhooks for Monero & Zcash (below). Also free and public: DeFi-liquidation telemetry (Aave, Morpho, Spark, Compound) and Ethereum block-builder market share from our own shadow recorder. No signup, no API key.
@OrknetP on Telegram.
— or open the
live stats dashboard
to see the data without writing a single line.
Private Watch — the headline product
Get an HMAC-signed webhook the instant a Monero or Zcash payment lands at your address. You supply a view key (read-only, cannot spend), an address, and a webhook URL. We POST you a notification on every balance change. Prepaid credit meter: $0.02 per day idle + $0.005 per webhook delivered — no account, no API key, no node.
Who it’s for: merchants accepting XMR or ZEC, donation pages, tip jars, payment bots, anyone selling something off-platform who would rather not run a 100 GB monerod or 300 GB zebra just to know whether the customer paid. View keys never let us move funds; if our DB leaks we can’t spend anything.
How the meter works: the first $0.10 (paywall on watch creation) buys 5 idle days. After that, top up any amount via dedicated paywalled paths: $0.10, $1.00, or $5.00 a pop. Every webhook body carries a credit block so your receiver always knows how much it has left. We’ll fire one low_credit warning when you have ~2 idle days remaining, even if no payments have come in.
Pay in privacy coin, not just USDC. A Monero/Zcash service that only took stablecoins on a transparent chain would be missing the point. So you can top a watch up by sending XMR or ZEC directly: POST /v1/private/topup-crypto is free to call and returns a receiving address plus the exact amount to send (Monero uses a unique-amount invoice tag; Zcash uses a memo) at a USD rate locked for the quote window. We detect your payment with the same view-key scanner this product sells — dogfooding the whole way down — and we hold only a view key for that wallet, never a spend key. No wallet connection, no x402, no API key.
Why it’s cheap: small users pay cents per month even with no traffic. Heavy users pay a few dollars even after thousands of webhook deliveries. Compare to a self-hosted full node (~$30/mo VPS + storage), light-wallet subscriptions ($5–$50/mo), or merchant gateways (1–2%): the only ones with skin in the game.
# 1. Create a watch (one x402 payment of $0.10 seeds $0.10 credit)
curl -s https://api.seneschal.space/v1/private/watch \
-X POST -H 'content-type: application/json' \
-H 'x-payment: <eip3009 payload, $0.10 USDC on Base>' \
-d '{
"chain": "monero",
"address": "44AFFq…",
"viewKey": "0123…",
"webhookUrl": "https://shop.example.com/webhook/xmr"
}'
# 2. Top up later (a $1 top-up buys ~50 idle days):
curl -X POST https://api.seneschal.space/v1/private/topup-1 \
-H 'x-payment: <eip3009 payload, $1.00 USDC on Base>' \
-H 'content-type: application/json' \
-d '{"watchId":"...","watchToken":"..."}'
# 2b. ...or pay in Monero/Zcash instead (FREE quote, no x402, no key):
curl -X POST https://api.seneschal.space/v1/private/topup-crypto \
-H 'content-type: application/json' \
-d '{"watchId":"...","watchToken":"...","chain":"monero","amountUsdCents":500}'
# -> { quoteId, payTo, amount:{display,coin}, memo, confirmations, expiresAt }
# Send the exact amount (Monero) or include the memo (Zcash), then poll:
curl -s -H 'x-watch-token: ...' \
https://api.seneschal.space/v1/private/topup-crypto/<quoteId>
# 3. One-off historical lookup (returns notes; view key never persists):
curl -X POST https://api.seneschal.space/v1/private/historical \
-H 'x-payment: <eip3009 payload, $0.50 USDC on Base>' \
-H 'content-type: application/json' \
-d '{"chain":"zcash","address":"u1...","viewKey":"uview1...","includeNotes":true}'
# 4. FREE: derive a Zcash UFVK from a BIP-39 mnemonic (loud warning, rate-limited):
curl -X POST https://api.seneschal.space/v1/private/derive-viewkey \
-H 'content-type: application/json' \
-d '{"chain":"zcash","phrase":"abandon abandon ... 24 words"}'
Open WalletConnect panel » Full integration guide Free derive form /v1/private/info Live counters
Four endpoints, one prepaid balance
Create a watch
$0.10 · x402 · seeds $0.10 credit
POST /v1/private/watch — HMAC-signed webhook on every balance change. View key encrypted at rest, polled every 3 min.
Top up credit
USDC (x402) or XMR/ZEC · any amount
POST /v1/private/topup{,-1,-5,-custom} — $1 buys ~50 idle days. Or pay in coin (free quote) via POST /v1/private/topup-crypto. low_credit webhook tells you when to top up.
Historical lookup
$0.50 · one-off · view key in-memory only
POST /v1/private/historical — returns received / spent / spendable totals and optional per-note breakdown. Auto-detects birthday for Zcash.
Derive view key
FREE · 6/min/IP · Zcash UFVK from a phrase
POST /v1/private/derive-viewkey — forwards a BIP-39 phrase to the local orchard-scanner. Try it in-page below.
Try the free derive endpoint in-page (no x402 payment, no curl)
Calls POST /v1/private/derive-viewkey directly from this page. Returns a read-only Unified Full Viewing Key (UFVK) that you can plug into /v1/private/watch or /v1/private/historical.
abandon abandon … abandon art (24 words) — it’s a public test vector and grants nothing.Why this exists
Seneschal runs an Ethereum block builder and a vertically-integrated liquidation searcher. As a side effect of doing our own work we continuously track ~500 Morpho borrowers, 1,300+ Spark borrowers, every Aave V3 mainnet position with non-trivial debt, and the winning builder of every slot since May 2026. Nobody else publishes this combination, so we expose it.
Two protocols, same backend:
- REST API at
https://api.seneschal.space— for dashboards, monitoring tools, anything that speaks HTTP. - MCP server at
https://mcp.seneschal.space— for AI agents (Claude, Cursor, Continue, etc.) using the Model Context Protocol.
Quick start
REST
curl https://api.seneschal.space/v1/liquidations/atrisk?max_hf=1.05
MCP (Claude Desktop / Cursor)
Add this to your MCP client config (e.g. ~/.cursor/mcp.json):
{
"mcpServers": {
"seneschal-data": {
"url": "https://mcp.seneschal.space/"
}
}
}
The full Seneschal tool surface becomes available to your agent:
seneschal_health,
seneschal_list_at_risk_borrowers,
seneschal_list_borrowers,
seneschal_recent_liquidations,
seneschal_get_borrower,
seneschal_get_borrower_history,
seneschal_builder_leaderboard,
seneschal_stats_overview,
seneschal_flashloan_providers,
seneschal_q (Penny Oracle dispatcher),
plus the Private Watch suite:
seneschal_private_watch_info,
seneschal_private_watch_create,
seneschal_private_watch_topup,
seneschal_private_watch_topup_crypto,
seneschal_private_watch_historical,
seneschal_private_watch_derive_viewkey,
seneschal_private_watch_status,
seneschal_private_watch_cancel and
seneschal_private_watch_test.
REST endpoints
/v1/health
Service liveness plus row counts and data-source mtimes. Useful for both monitoring probes and confirming freshness before consuming downstream data.
/v1/liquidations/atrisk
Current snapshot of borrowers near liquidation, sorted by ascending health factor.
| Query param | Type | Default | Notes |
|---|---|---|---|
protocol | enum | (all) | aave, morpho, spark, or compound |
max_hf | number | (none) | Return only positions with health factor strictly below this. |
min_debt_usd | number | 0 | Filter out dust. |
limit | 1..500 | 50 | Max rows. |
/v1/liquidations/recent
Liquidations observed in the recent past. Each row's outcome field is either won_by_other (a competitor liquidator landed) or we_landed (Seneschal's own searcher won it).
| Query param | Type | Default | Notes |
|---|---|---|---|
since_ms | epoch ms | now − 24h | |
protocol | enum | (all) | |
limit | 1..500 | 50 |
/v1/borrowers
Discovery endpoint: list borrowers from Aave / Morpho without knowing addresses in advance. Supports HF range, debt range, sort field/direction and offset pagination.
| Query param | Type | Default | Notes |
|---|---|---|---|
protocol | enum | (all) | aave, morpho, compound |
min_hf | number | (none) | Inclusive lower bound. |
max_hf | number | (none) | Exclusive upper bound. |
min_debt_usd | number | 0 | |
max_debt_usd | number | (none) | |
sort_by | enum | health_factor | health_factor, debt_usd, collateral_usd, last_observed_ms |
sort_dir | enum | asc | asc or desc |
limit | 1..500 | 50 | |
offset | integer | 0 | For pagination. |
/v1/borrowers/:address
Combined snapshot for one borrower across every protocol where we have data.
/v1/borrowers/:address/history
Per-block historical health-factor traces for one borrower.
| Query param | Type | Default | Notes |
|---|---|---|---|
protocol | enum | (required) | aave or morpho (Spark history not retained as SQL). |
since_ms | epoch ms | now − 7d | |
until_ms | epoch ms | now | |
granularity | enum | raw | raw, hour, or day |
limit | 1..500 | 500 |
/v1/builders/leaderboard
Block-builder market share derived from our own slot-by-slot shadow recorder. Cached for 60s.
| Query param | Type | Default | Notes |
|---|---|---|---|
window | enum | 24h | 24h, 7d, 30d, all |
limit | 1..500 | 20 | Top-N builders to return. |
/v1/stats/overview
Single bundled endpoint feeding the public stats dashboard: totals, health-factor histogram, top-10 at-risk, 30-day liquidation counts, builder share for 24h/7d/30d, and recent liquidations — all in one call so the dashboard renders in one round trip.
/v1/flashloan/providers
Curated catalogue of Ethereum mainnet flash-loan providers (Aave V3, Balancer V2, Morpho Blue, Uniswap V3, FlashBank) with current fee in basis points, contract addresses, qualitative liquidity notes, and per-provider caveats. Helpful for searchers picking the cheapest viable provider for a liquidation.
| Query param | Type | Default | Notes |
|---|---|---|---|
chain | string | ethereum | Only ethereum is catalogued today. |
max_fee_bps | number | (none) | Drop providers whose flat fee exceeds this (1bp = 0.01%). |
multi_asset | bool | (any) | If true, only return providers that support borrowing multiple assets in one flash loan. |
Worked example
Find the most at-risk Aave borrower right now and pull their HF history:
$ curl -s 'https://api.seneschal.space/v1/liquidations/atrisk?protocol=aave&limit=1' | jq '.results[0]'
{
"borrower": "0x...",
"protocol": "aave",
"health_factor": 1.011,
"collateral_usd": 8412055,
"debt_usd": 8240015,
"liquidatable": false,
...
}
$ curl -s "https://api.seneschal.space/v1/borrowers/0x.../history?protocol=aave&granularity=hour"
{ "address": "0x...", "points": [ ... 168 hourly observations ... ] }
MCP tool reference
Identical surface to REST: every endpoint has a matching tool with the same parameters and same response shape (just wrapped as MCP tool content).
| Tool | Use |
|---|---|
seneschal_health | Liveness + freshness probe. |
seneschal_list_at_risk_borrowers | Find liquidatable positions across all DeFi. |
seneschal_list_borrowers | Discovery / pagination over the full borrower set with HF + debt range filters. |
seneschal_recent_liquidations | Recent on-chain liquidation events. |
seneschal_get_borrower | Latest state of one borrower across protocols. |
seneschal_get_borrower_history | Time-series HF traces. |
seneschal_builder_leaderboard | Ethereum builder market share. |
seneschal_stats_overview | One-call aggregate bundle powering the public dashboard. |
seneschal_flashloan_providers | Curated catalogue of mainnet flash-loan providers (Aave, Balancer, Morpho, Uniswap V3, FlashBank). |
seneschal_paywall_info | Free. Describes the live x402 paywall (network, recipient, per-call price, MCP tool name) for the premium tier. |
seneschal_premium_opportunities | Premium. Uncapped at-risk catalogue ranked by expected value, with realised 7d market intel. Paid via x402 at the REST surface. |
Premium tier (x402) — LIVE
Pay-per-call endpoints on Base mainnet, settled in USDC via the x402 protocol. Three price tiers — bulk feeds, builder analytics, and atomic single-fact queries:
| Endpoint | Price | What you get |
|---|---|---|
GET /v1/premium/opportunities |
$0.05 | Uncapped at-risk borrower catalogue plus realised 7-day market
intel (top liquidators, per-market win rate, our own attempt outcomes),
ranked by expected liquidation value. Honest value-add over the free
500-row, snapshot-only /v1/liquidations/atrisk. |
GET /v1/premium/builder-stats |
$0.10 | Per-builder bid distribution (p25/median/p75/p90/p99/max ETH) plus a 24-element hourly slot histogram over a configurable window. Answers "what value do I need to land in builder X's bundle right now?" for searchers tuning bundle pricing. Sourced from our own shadow recorder so it covers every observed slot, not just landed blocks. |
GET /v1/premium/counter-mev |
$0.05 | Counter-MEV / approval-risk feed. Uncapped, risk-scored
set of malicious approval-harvesting spender contracts (the
JaredFromSubway $7.5M drain pattern — standard ERC-20 approvals,
not a contract-gate bypass), honeypot/bait tokens (fake fWETH/fUSDC
lookalikes, Salmonella-style fee-on-transfer & sell-revert traps), and
live dangling approvals at risk. Filter ?category=&min_score=&limit=.
Free summary + teaser at GET /v1/counter-mev/summary; live
dashboard at counter-mev.seneschal.space. |
GET /v1/q/* (15 endpoints) |
$0.001 | Penny Oracle. Atomic single-fact endpoints — each answers ONE yes/no or one number, returns in <50 ms, and is designed for tight agent loops where bulk JSON is overkill. See the catalogue below. |
POST /v1/private/watch |
$0.10 | Private Watch — create. Subscribes a Monero or Zcash address to view-key based payment monitoring. $0.10 buys the watch + $0.10 of opening credit. Credit meter runs at $0.02/day idle + $0.005/webhook delivered. View keys are AES-256-GCM encrypted at rest with an operator-supplied master key. See private watch below. |
POST /v1/private/topup — $0.10POST /v1/private/topup-1 — $1.00POST /v1/private/topup-5 — $5.00POST /v1/private/topup-custom — any $0.10–$25 |
tiered | Top up an existing watch (USDC via x402). Explicit tiers so the x402 paywall can quote each price up front. $0.10 buys ~5 idle days, $1.00 buys ~50, $5.00 buys ~250; topup-custom takes any amount. Body: {watchId, watchToken} (plus amountAtomic for custom). |
POST /v1/private/topup-cryptoGET /v1/private/topup-crypto/:quoteId |
FREE quote (pay in coin) |
Top up by paying in Monero/Zcash. The POST is free and returns a quote — a receiving address, the exact coin amount to send (Monero: a unique-amount invoice tag; Zcash: a memo), and a USD rate locked for ~15 min. Send the payment, then poll the GET (header x-watch-token) until status=settled. We detect it with our own view-key scan and credit the watch after the stated confirmations; we never hold a spend key. Body: {watchId, watchToken, chain, amountUsdCents} ($2–$500). |
POST /v1/private/historical |
$0.50 | One-off scan. Returns all spendable + spent notes for a view key without setting up a watch. View key streams to NFPT in memory only — never written to our SQLite or logs. Body: {chain, address, viewKey, birthdayHeight?, toHeight?, includeNotes?}. |
POST /v1/private/derive-viewkey |
FREE | BIP-39 → UFVK derivation (Zcash). Rate-limited to 6/min/IP. Forwards a 12- or 24-word seed phrase to NFPT’s orchard-scanner CLI and returns the matching read-only Unified Full Viewing Key. Loud security warning in the response — the phrase transits our server (no logging, no persistence) but a network observer between you and us would see the bytes; derive offline if you can. |
Penny Oracle — /v1/q/* atomic-fact endpoints
Seventeen micro-priced endpoints, all GET, all $0.001
per call (1/100th of a cent). Each returns a flat object so an agent
can branch directly on the answer without nested-field gymnastics.
The free catalogue at GET /v1/q enumerates every question
and its input parameters.
| Endpoint | Inputs | Answers |
|---|---|---|
/v1/q/liquidatable | addr, protocol? | Is borrower X liquidatable right now? Returns {found, liquidatable, hf, debt_usd, last_seen_ms} across Aave + Morpho. |
/v1/q/at-risk-count | max_hf?, min_debt_usd?, protocol? | Count + total debt of borrowers below the named HF and above the named debt floor. |
/v1/q/recent-liquidations | since_min?, protocol? | Number of liquidations observed in the last N minutes and their aggregate debt. |
/v1/q/top-builder | window? | Highest-share builder in the named window (24h/7d/30d). |
/v1/q/builder-share | builder, window? | Slot share of a specific builder (substring match) over the window. |
/v1/q/builder-bid | builder, pct?, window? | Percentile bid value (in ETH) for that builder over the window. Use pct 25/50/75/90/99. |
/v1/q/block-value | window?, pct? | Network-wide percentile block value (proposer payment, ETH) across all winning slots in the window — the "is it worth bundling?" number. |
/v1/q/cheapest-flashloan | asset, chain? | Cheapest flash-loan provider for that asset on that chain. Defaults to Ethereum mainnet. |
/v1/q/data-freshness | source | Age in seconds of the freshest row in one of: shadow_blocks, borrower_snapshot, morpho_borrower_snapshot, missed_liquidations, executions. |
| Privacy-chain facts — sourced from Seneschal-operated full nodes | ||
/v1/q/xmr/height | — | Current Monero chain height + sync state. Sourced from a synced monerod v0.18 instance. |
/v1/q/xmr/mempool | — | Number of pending transactions in the Monero mempool right now. |
/v1/q/xmr/fee | — | Recommended per-byte fee in piconero (also per-kB) so wallets can budget the next-block tx. |
/v1/q/xmr/fee-estimate | — | Actionable Monero fee estimate: per-byte fee × a typical 1500-byte tx, broken out by priority level, in piconero and XMR. |
/v1/q/xmr/last-block | — | Timestamp + age of the most recent Monero block, plus hash, difficulty, size. |
/v1/q/zec/height | — | Current Zcash chain height + verification progress + best block hash. Sourced from a synced zebra node. |
/v1/q/zec/mempool | — | Zcash mempool count + bytes. |
/v1/q/zec/last-block | — | Timestamp + age of the most recent Zcash block, plus hash, difficulty, size. |
The privacy-chain set is the "joining the dots" of this product line: Monero and Zcash are the two chains where running a node yourself is genuinely awkward (~108 GB and ~270 GB respectively, plus syncing hours), public RPC endpoints rate-limit aggressively, and there is no Etherscan-style hosted explorer to fall back on. We run synced nodes already; the x402 sub-cent paywall finally makes selling individual reads worth the trouble. All responses are cached server-side for 10 s so an agent in a tight loop costs the daemon nothing extra.
Hand-rolled flow:
curl -s 'https://api.seneschal.space/v1/q/liquidatable?addr=0x...&protocol=aave'
# Pays $0.001 USDC on Base via x402-fetch and returns
# {"found":true,"protocol":"aave","liquidatable":false,"hf":1.03,"debt_usd":24500,"last_seen_ms":1716314400000}
MCP agents can use the single dispatcher tool seneschal_q
with {question, params} rather than wiring up separate
tool calls per question. The MCP path is currently free; the HTTP path
is paywalled.
Payment uses the x402 protocol
(spec v2). Unsigned requests get HTTP 402 with a base64-encoded
Payment-Required header carrying machine-readable
PaymentRequirements; the client signs an EIP-3009
transferWithAuthorization off-chain and retries with a
X-PAYMENT header. We delegate verify + settle to
Coinbase’s CDP
facilitator, which broadcasts the EIP-3009 transfer on Base. No API
keys for the payer, no subscriptions, no gas for the payer — the
facilitator pays the gas. (Settling through Coinbase also lists the
service in the Coinbase x402 Bazaar.)
Free metadata endpoint for budgeting before any paid call:
curl https://api.seneschal.space/v1/paywall
# → {"protocol":"x402","network":"eip155:8453",
# "facilitator":"https://api.cdp.coinbase.com/platform/v2/x402",
# "facilitator_mode":"cdp",
# "payTo":"0x46Ba634261566CF242c853d1f49511f9268ba674",
# "scheme":"exact (EIP-3009 transferWithAuthorization)",
# "routes":[{"endpoint":"GET /v1/premium/opportunities","price":"$0.05",...},
# {"endpoint":"GET /v1/premium/builder-stats","price":"$0.10",...},
# {"endpoint":"GET /v1/q/liquidatable","price":"$0.001",...}, … ]}
Agents using x402-axios, x402-fetch,
@x402/express, @x402/fastify or the
official client libraries pay automatically on 402. Hand-rolled flow,
in three lines of TypeScript:
import { wrapFetchWithPayment } from 'x402-fetch';
import { createWalletClient, http } from 'viem';
import { base } from 'viem/chains';
const wallet = createWalletClient({ account, transport: http(), chain: base });
const fetchPaid = wrapFetchWithPayment(fetch, wallet);
const r = await fetchPaid('https://api.seneschal.space/v1/premium/opportunities');
console.log(await r.json());
The account is any viem-compatible signer holding a small
USDC balance on Base — a fresh EOA + 1 USDC will fund ~20 paid calls.
Private Watch — /v1/private/* (XMR/ZEC payment monitoring)
This is the headline product. The agent (or merchant, or wallet) hands us a
public address, a view key, and a webhook URL. We scan every
new block against the view key on the local NFPT wallet-scanner
(driven by monerod for Monero and zebra + the
Zcash orchard-scanner binary for Zcash) and POST a signed event
to the webhook the moment the balance changes.
Pricing — prepaid credit meter. One payment of $0.10
opens a watch and seeds $0.10 of credit. The watch then drains at $0.02
per UTC day idle (proportional, billed each poll tick) plus
$0.005 per webhook delivered. When credit hits a low threshold
($0.05) we POST a one-shot low_credit warning so your receiver can
top up before going silent. Top up any time with one of three paywalled paths
($0.10 / $1 / $5). Credit balance is in every webhook body so well-behaved
receivers can ignore the dedicated event.
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/v1/private/watch | POST | x402 $0.10 | Create a watch with $0.10 of starter credit. Body: {chain, address, viewKey, webhookUrl, birthdayHeight?}. Returns {watchId, watchToken, webhookSecret, expiresAt, creditAtomic, ratePerDayAtomic, ratePerCallAtomic, topupEndpoints, testEndpoint}. durationDays is silently ignored for backward compatibility — the credit meter is the only knob now. |
/v1/private/topup | POST | x402 $0.10 | Adds $0.10 of credit (~5 idle days). Body: {watchId, watchToken}. |
/v1/private/topup-1 | POST | x402 $1.00 | Adds $1.00 of credit (~50 idle days). |
/v1/private/topup-5 | POST | x402 $5.00 | Adds $5.00 of credit (~250 idle days). |
/v1/private/historical | POST | x402 $0.50 | One-off historical scan. Returns spendable + spent + total-received totals (and optionally per-note breakdowns). View key streams to NFPT in-memory only — never written to our SQLite or logs. |
/v1/private/derive-viewkey | POST | FREE (6/min/IP) | Zcash only. Derives a UFVK from a BIP-39 mnemonic via NFPT’s orchard-scanner. Phrase transits in-memory; we do not log or persist. Use offline derivation where possible. |
/v1/private/watch/:id | GET | header x-watch-token | Read current status: credit block (remaining / days_remaining / low-credit flag), last polled time, delivery count, last event type, last known balance snapshot, ETA to next poll. Free. |
/v1/private/watch/:id | DELETE | header x-watch-token | Cancel a watch (any remaining credit is forfeited — this is by design to avoid refund accounting and chargebacks). Free. |
/v1/private/watch/:id/test | POST | header x-watch-token | Fires one synthetic webhook so you can verify your signature handling and receiver before relying on real payments. Stamped event: synthetic_test so well-behaved receivers can branch and skip processing. Free. |
/v1/private/info | GET | — | Free metadata: current prices, supported chains, top-up tiers, upstream NFPT health, security notes. |
/v1/private/health | GET | — | Counters only (no PII) for ops monitoring — includes credit aggregates. |
Webhook contract. Every delivery is a POST with
content-type: application/json and three Seneschal headers:
X-Seneschal-Watch-Id: <uuid>
X-Seneschal-Event: balance_change | scan_complete | status_change | low_credit | synthetic_test
X-Seneschal-Signature: sha256=<HMAC-SHA256(webhookSecret, exact request body)>
The body is plain JSON. Every delivery (including low_credit
warnings) carries a credit block so receivers always know
where they stand:
{
"watchId": "fb1a29bd-…",
"chain": "monero",
"address": "46FzbF…",
"event": "balance_change",
"timestamp": "2026-05-21T08:06:54.626Z",
"nonce": "mpf7j7he-30s7yx",
"previous": { "balanceAtomic": "0", "scannedHeight": 3349800, … },
"current": { "balanceAtomic": "1234567890", "scannedHeight": 3349881, … },
"delta": {
"balance_atomic": "1234567890",
"before_atomic": "0",
"after_atomic": "1234567890"
},
"credit": {
"remaining_atomic": "94750",
"remaining_usd": "0.0948",
"days_remaining": 4.7,
"low_credit": false,
"rate_per_day_atomic": "20000",
"rate_per_call_atomic": "5000",
"low_credit_threshold_atomic": "50000"
}
}
The low_credit event is fired once when
remaining_atomic first drops below the threshold ($0.05 of
credit, ~2.5 idle days). Top up >= the threshold to re-arm the
warning. After credit reaches zero the watch stops being polled
entirely; no further deliveries happen until the next top-up.
Receivers verify the signature with the per-watch
webhookSecret returned at creation. Constant-time HMAC comparison
defeats forgery; the secret is generated server-side and never reused across
watches. Bodies are capped at 64 KB.
Security model. View keys decrypt incoming transactions but
cannot spend — you can hand us one without giving up custody. We
nonetheless encrypt the key at rest with AES-256-GCM under an operator-held
master key (PRIVATE_WATCH_ENCRYPTION_KEY); plaintext only exists in
memory while the poller is decrypting it for the next scan call. Webhook URLs
are vetted at creation:
- HTTPS-only in production (
http://rejected unless the operator opts in for local dev). - SSRF guard rejects RFC1918, loopback, link-local, RFC6598 CGNAT, IPv6 unique-local / link-local / loopback, and cloud-metadata IPs.
- DNS-resolve-and-recheck — we resolve the hostname and re-test every returned A/AAAA against the same blocklist, so
evil.example.comcan’t alias to127.0.0.1. - No userinfo — URLs containing
https://user:pass@…are rejected so we never echo credentials onto the wire.
Tunables. Polling cadence is 3 min by default (stays inside
NFPT's 5 min scanner idle window). Webhook receivers get an 8 s
HTTP timeout and we cap drained response body at 4 KB to defeat
slow-loris megabyte responses. On webhook failure we retry on the next tick;
50 consecutive failures retire the watch with a dead flag. After
expiry the row is hard-deleted on the next tick.
Zcash birthday height. If omitted we default to NU6
(3,042,000) so the scanner never trips into a multi-hour
autoDetect backwards-walk. Wallets created before April 2024
should pass an explicit birthdayHeight matching wallet age.
MCP. Agents already inside a paid MCP session can use
seneschal_private_watch_create,
seneschal_private_watch_topup,
seneschal_private_watch_topup_crypto,
seneschal_private_watch_historical,
seneschal_private_watch_derive_viewkey,
seneschal_private_watch_status,
seneschal_private_watch_cancel and
seneschal_private_watch_info for end-to-end flow without
direct HTTP.
Historical lookups & view-key derivation
Two new on-demand services let agents recover state without committing to a long-running watch:
POST /v1/private/historical— $0.50 one-off. For Zcash we run an Orchard scan withautoDetect: true(birthday height auto-discovered) andwitness: trueso the response includes per-note anchor + Merkle-path data alongside totals. For Monero we use the fullmonero-lwsscan and aggregate incoming + outgoing notes intoreceived_atomic/spent_atomic/spendable_atomic. View keys stream through the upstream NFPT API in-memory only — never written to our SQLite, never logged.POST /v1/private/derive-viewkey— FREE. Zcash only. Forwards a 12- or 24-word BIP-39 mnemonic to NFPT’sorchard-scanner derive-ufvkcommand and returns the matching read-only UFVK plus optional Sapling + transparent FVKs. Loud security warning in the response: the seed phrase transits our server (we never log or persist it, but a TLS-MitM on the network path would see the bytes). Whenever feasible, runorchard-scannerlocally and supply the resulting UFVK directly. Rate-limited to 6 requests per IP per minute.
Data freshness & coverage
- Aave V3 mainnet — live, latest health factor refreshed every block for borrowers with non-trivial debt.
- Morpho Blue mainnet — live, latest snapshot ~10 minutes old.
- Spark — snapshot refreshed periodically; check
/v1/health'sspark_borrowers_mtime_ms. - Compound — merged into the Aave snapshot table by the upstream writer; query with
protocol=aave. - Shadow blocks — one row per slot since May 2026 (~55k rows at launch, growing). Built from our own observation of relay-served payloads, not relay self-reporting.
Limits, terms, fair use
- 120 req/min per IP, soft. Heavy users should ask for an allow-list bump on Telegram (
@OrknetP). - No SLA. This is a free best-effort service. Expect occasional restarts.
- Use of the data must not violate any privacy or legal restrictions in your jurisdiction. We surface only on-chain data and our own observations.
- Crediting Seneschal (
https://seneschal.space) in derived work is appreciated but not required.
About
Seneschal is a single-operator Ethereum block builder and searcher
running an rbuilder fork from a co-located server in
Helsinki. Builder on-chain extra_data is Seneschal/0.1.
Contact @OrknetP on Telegram. By using the service you agree to the Terms and Privacy policy.