Skip to content

Commit dddc3bc

Browse files
author
S. K. Rotwang MMMMMMMMM
committed
feat(discovery): privacy-coin-first metadata + crawlability
- x402: PREMIUM_ROUTES now lead with Private Watch (Monero/Zcash) then privacy-chain facts, DeFi feeds after; add qFact() helper (DRY) - docs: lead <title>/description with Monero/Zcash payment webhooks; add OpenGraph + Twitter cards + JSON-LD (WebAPI) on landing + docs - add llms.txt, robots.txt, sitemap.xml for AI-crawler + SEO discovery - publish-docs: map the new crawlability files to apex + docs subdomain
1 parent 521ac4e commit dddc3bc

8 files changed

Lines changed: 171 additions & 73 deletions

File tree

docs/index.html

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,29 @@
33
<head>
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width,initial-scale=1">
6-
<title>Seneschal Data API</title>
7-
<meta name="description" content="Free public REST and MCP API exposing real-time and historical liquidation telemetry for Aave, Morpho, Spark and Compound on Ethereum mainnet.">
6+
<title>Seneschal — Monero &amp; Zcash payment webhooks (view-key, no node)</title>
7+
<meta name="description" content="Get an HMAC-signed webhook the moment a Monero or Zcash payment lands at your address — using only a read-only view key, no node to run. Pay-per-call in USDC via x402; free read tier, no signup. Plus an Ethereum block builder and free DeFi liquidation telemetry.">
8+
<link rel="canonical" href="https://docs.seneschal.space/">
9+
<meta property="og:type" content="website">
10+
<meta property="og:site_name" content="Seneschal">
11+
<meta property="og:url" content="https://docs.seneschal.space/">
12+
<meta property="og:title" content="Monero &amp; Zcash payment webhooks — view-key only, no node">
13+
<meta property="og:description" content="A webhook the instant an XMR or ZEC payment lands at your address, from a read-only view key. Pay-per-call in USDC (x402); free read tier, no signup or API key.">
14+
<meta name="twitter:card" content="summary">
15+
<meta name="twitter:title" content="Monero &amp; Zcash payment webhooks — view-key only, no node">
16+
<meta name="twitter:description" content="A webhook the instant an XMR or ZEC payment lands at your address, from a read-only view key. Pay-per-call in USDC (x402); free read tier.">
17+
<script type="application/ld+json">
18+
{
19+
"@context": "https://schema.org",
20+
"@type": "WebAPI",
21+
"name": "Seneschal Data API",
22+
"description": "View-key payment webhooks for Monero and Zcash, plus Ethereum builder and DeFi liquidation data. Pay-per-call via x402 USDC on Base; free read tier; MCP server for AI agents.",
23+
"documentation": "https://docs.seneschal.space/",
24+
"provider": { "@type": "Organization", "name": "Seneschal", "url": "https://seneschal.space" },
25+
"termsOfService": "https://seneschal.space/terms.html",
26+
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD", "description": "Free read tier; premium endpoints pay-per-call in USDC via x402." }
27+
}
28+
</script>
829
<style>
930
:root {
1031
--fg: #1a1a1a;
@@ -57,10 +78,11 @@
5778

5879
<h1>Seneschal Data API</h1>
5980
<p class="muted">
60-
Free, public, read-only HTTP and Model Context Protocol API exposing
61-
real-time and historical DeFi liquidation telemetry for Aave, Morpho,
62-
Spark and Compound on Ethereum mainnet, plus block-builder market share
63-
data from our own shadow recorder.
81+
Pay-per-call data over HTTP and the Model Context Protocol. The headline
82+
product is <strong>Private Watch</strong> &mdash; view-key payment webhooks for
83+
Monero &amp; Zcash (below). Also free and public: DeFi-liquidation telemetry
84+
(Aave, Morpho, Spark, Compound) and Ethereum block-builder market share from
85+
our own shadow recorder. No signup, no API key.
6486
</p>
6587

6688
<div class="callout callout-info">

docs/landing.html

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,30 @@
22
<html lang="en">
33
<head>
44
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width,initial-scale=1">
56
<title>Seneschal — Private Watch + Ethereum block builder</title>
67
<meta name="description" content="Get a webhook the moment a Monero or Zcash payment lands at your address, using only the (read-only) view key. $0.02/day idle + $0.005/webhook delivered via x402 USDC on Base. Plus an Ethereum mainnet block builder and free liquidation telemetry.">
8+
<link rel="canonical" href="https://seneschal.space/">
9+
<meta property="og:type" content="website">
10+
<meta property="og:site_name" content="Seneschal">
11+
<meta property="og:url" content="https://seneschal.space/">
12+
<meta property="og:title" content="Private Watch — Monero &amp; Zcash payment webhooks, view-key only">
13+
<meta property="og:description" content="Get pinged the instant an XMR or ZEC payment lands at your address — from a read-only view key, no node to run. $0.02/day + $0.005/webhook in USDC via x402. No signup, no API key.">
14+
<meta name="twitter:card" content="summary">
15+
<meta name="twitter:title" content="Private Watch — Monero &amp; Zcash payment webhooks, view-key only">
16+
<meta name="twitter:description" content="Get pinged the instant an XMR or ZEC payment lands at your address — from a read-only view key, no node. Pay-per-use in USDC via x402. No signup.">
17+
<script type="application/ld+json">
18+
{
19+
"@context": "https://schema.org",
20+
"@type": "WebAPI",
21+
"name": "Seneschal Private Watch",
22+
"description": "View-key payment webhooks for Monero and Zcash: an HMAC-signed webhook the instant a payment lands at your address, from a read-only view key. Pay-per-call in USDC via x402 on Base; free read tier; MCP server for AI agents.",
23+
"url": "https://seneschal.space/",
24+
"documentation": "https://docs.seneschal.space/",
25+
"provider": { "@type": "Organization", "name": "Seneschal", "url": "https://seneschal.space" },
26+
"termsOfService": "https://seneschal.space/terms.html"
27+
}
28+
</script>
729
<style>
830
:root {
931
--bg: #fff;

docs/llms.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Seneschal
2+
3+
> View-key payment webhooks for Monero and Zcash, plus an Ethereum mainnet block builder and free DeFi-liquidation telemetry. Pay-per-call in USDC via the x402 standard; free read tier; an MCP server for AI agents (no API key).
4+
5+
Seneschal lets a receiver get an HMAC-signed webhook the instant a Monero (XMR) or Zcash (ZEC) payment lands at their address, using only a read-only *view key* — no node to run, no custody (view keys cannot spend). Premium endpoints are paid per call in USDC on Base via the x402 protocol; many read endpoints are free.
6+
7+
## Private Watch — Monero / Zcash payment webhooks (headline product)
8+
- Docs & quickstart: https://docs.seneschal.space/
9+
- Create a watch: POST https://api.seneschal.space/v1/private/watch (x402, $0.10 seeds credit) — body { chain, address, viewKey, webhookUrl }. Returns a webhookSecret; verify deliveries with HMAC-SHA256.
10+
- Top up credit: POST https://api.seneschal.space/v1/private/topup | /topup-1 | /topup-5
11+
- One-off historical scan: POST https://api.seneschal.space/v1/private/historical (x402)
12+
- Free UFVK derivation from a seed phrase (rate-limited): POST https://api.seneschal.space/v1/private/derive-viewkey
13+
14+
## API discovery
15+
- x402 payment manifest: https://api.seneschal.space/.well-known/x402
16+
- Health + table sizes: https://api.seneschal.space/v1/health
17+
- MCP server (Streamable HTTP transport): https://mcp.seneschal.space/
18+
- Live stats dashboard: https://stats.seneschal.space/
19+
- WalletConnect control panel: https://panel.seneschal.space/
20+
21+
## Pricing
22+
- Private Watch: $0.02 per idle day + $0.005 per webhook delivered; creation seeds $0.10 credit; top-ups of $0.10 / $1 / $5.
23+
- Atomic "single-fact" endpoints (Monero/Zcash chain facts; DeFi facts): about $0.001 each, ideal for agent loops.
24+
25+
## Free / public (no key)
26+
- DeFi liquidation telemetry for Aave, Morpho, Spark and Compound on Ethereum mainnet.
27+
- Ethereum block-builder market-share data from the Seneschal shadow recorder.
28+
29+
## Contact & policies
30+
- Telegram: https://t.me/OrknetP
31+
- Terms: https://seneschal.space/terms.html
32+
- Privacy: https://seneschal.space/privacy.html

docs/robots.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
User-agent: *
2+
Allow: /
3+
4+
Sitemap: https://seneschal.space/sitemap.xml

docs/sitemap.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3+
<url><loc>https://seneschal.space/</loc></url>
4+
<url><loc>https://docs.seneschal.space/</loc></url>
5+
<url><loc>https://stats.seneschal.space/</loc></url>
6+
<url><loc>https://panel.seneschal.space/</loc></url>
7+
<url><loc>https://seneschal.space/privacy.html</loc></url>
8+
<url><loc>https://seneschal.space/terms.html</loc></url>
9+
</urlset>

scripts/publish-docs.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ MAPPINGS=(
3333
"panel.html:panel/index.html"
3434
"privacy.html:privacy.html"
3535
"terms.html:terms.html"
36+
# Crawlability / AI-agent discovery — served at the apex domain, with
37+
# llms.txt + robots.txt also mirrored under the docs subdomain root.
38+
"llms.txt:llms.txt"
39+
"llms.txt:docs/llms.txt"
40+
"robots.txt:robots.txt"
41+
"robots.txt:docs/robots.txt"
42+
"sitemap.xml:sitemap.xml"
3643
)
3744

3845
echo "Publishing docs from ${REMOTE}:${SRC}/docs to ${REMOTE}:${WEB_ROOT}"

src/x402.js

Lines changed: 65 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -29,73 +29,35 @@ const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/u;
2929
// on eip155:8453 (Base) is supported.
3030
export const CDP_FACILITATOR_URL = 'https://api.cdp.coinbase.com/platform/v2/x402';
3131

32+
// Atomic single-fact ("Penny Oracle") routes all share the micro
33+
// price tier (`X402_Q_PRICE`, default $0.001) so agents can hammer
34+
// them in tight loops without subscription friction. Factored into a
35+
// helper so the privacy-chain and DeFi fact tables below stay
36+
// declarative and DRY. @x402/fastify matches `"METHOD /path"` exactly
37+
// (no wildcards), so each path is enumerated explicitly.
38+
const qFact = (path, description) => Object.freeze({
39+
method: 'GET',
40+
path,
41+
description,
42+
mimeType: 'application/json',
43+
priceEnvKey: 'X402_Q_PRICE'
44+
});
45+
3246
// Premium endpoints we'll wire up. Keep this in one place so the
3347
// systemd unit, the README, and the MCP tool descriptions all stay in
34-
// sync — touch one constant, the rest follow.
48+
// sync — touch one constant, the rest follow. Order is lead-product
49+
// first: the Monero/Zcash view-key payment webhooks (Private Watch)
50+
// and privacy-chain facts head the list because that's the
51+
// differentiated offering — so the discovery doc, MCP surface and
52+
// paywall description all present it first — with the DeFi-liquidation
53+
// and Ethereum-builder feeds after.
3554
export const PREMIUM_ROUTES = Object.freeze([
36-
Object.freeze({
37-
method: 'GET',
38-
path: '/v1/premium/opportunities',
39-
// Single source of truth for what the route returns and how
40-
// much it costs. The dashboard / docs / MCP tool can all
41-
// derive their copy from here.
42-
description: 'Top at-risk borrowers across Aave + Morpho + Spark with realised market success-rate, average actual profit-USD, and the builder most likely to land each market. Sorted by expected EV. Pure SQL, no live RPC.',
43-
mimeType: 'application/json',
44-
priceEnvKey: 'X402_FEED_PRICE'
45-
}),
46-
Object.freeze({
47-
method: 'GET',
48-
path: '/v1/premium/builder-stats',
49-
// Per-builder bid distribution (median/p90/p99/max) + hourly
50-
// slot activity histogram. Sourced from the Seneschal shadow
51-
// recorder so it covers every observed slot, not just landed
52-
// blocks. Tells searchers what value they need to outbid each
53-
// builder, segmented by hour of day. Useful for tuning bundle
54-
// bid pricing.
55-
description: 'Per-builder bid distribution (p25/median/p75/p90/p99/max) and hourly slot activity histogram from the Seneschal shadow recorder. Answers "what bid value do I need to land in builder X right now?" for searchers tuning bundle pricing.',
56-
mimeType: 'application/json',
57-
priceEnvKey: 'X402_BUILDER_STATS_PRICE'
58-
}),
59-
// Penny Oracle — atomic single-fact endpoints. Each priced at the
60-
// same micro tier (`X402_Q_PRICE`, default $0.001) so agents can
61-
// hammer them in tight loops without subscription friction. The
62-
// path family is enumerated explicitly because @x402/fastify
63-
// matches `"METHOD /path"` exactly, no wildcards.
64-
...[
65-
{ p: '/v1/q/liquidatable', d: 'Single-fact: is borrower X currently liquidatable? Returns {found, liquidatable, hf, debt_usd, last_seen_ms} sourced from Aave + Morpho snapshots.' },
66-
{ p: '/v1/q/at-risk-count', d: 'Single-fact: how many borrowers have HF < max_hf and debt >= min_debt_usd right now? Returns {count, total_debt_usd}.' },
67-
{ p: '/v1/q/recent-liquidations', d: 'Single-fact: how many on-chain liquidations have we observed in the last `since_min` minutes, with what aggregate debt? Returns {count, total_debt_usd}.' },
68-
{ p: '/v1/q/top-builder', d: 'Single-fact: which builder has the largest slot share in the named window (24h|7d|30d)? Returns {builder, share_pct, slots_won}.' },
69-
{ p: '/v1/q/builder-share', d: 'Single-fact: what share of slots in the window did `builder` win? Substring match.' },
70-
{ p: '/v1/q/builder-bid', d: 'Single-fact: percentile bid value (in ETH) for `builder` over the window. Returns {value_eth, samples}.' },
71-
{ p: '/v1/q/cheapest-flashloan', d: 'Single-fact: cheapest flash-loan provider for `asset` on `chain` (default ethereum). Returns {provider, fee_bps, address}.' },
72-
{ p: '/v1/q/data-freshness', d: 'Single-fact: age in seconds of the freshest record in the named source (shadow_blocks|borrower_snapshot|morpho_borrower_snapshot|missed_liquidations|executions).' },
73-
// Privacy-chain atomic facts. Sourced from our co-located
74-
// monerod + zebra full nodes; the equivalent thing you'd
75-
// otherwise need to run yourself (~108 GB Monero, ~270 GB
76-
// Zcash). Cached 10 s server-side so a hot agent loop
77-
// costs the daemon zero extra work.
78-
{ p: '/v1/q/xmr/height', d: 'Single-fact: current Monero chain height + sync status. Sourced from a live Seneschal-operated monerod node.' },
79-
{ p: '/v1/q/xmr/mempool', d: 'Single-fact: number of pending transactions in the Monero mempool right now.' },
80-
{ p: '/v1/q/xmr/fee', d: 'Single-fact: recommended Monero per-byte fee in piconero (also exposed per-kB for convenience).' },
81-
{ p: '/v1/q/xmr/last-block', d: 'Single-fact: timestamp + age of the most recent Monero block, plus hash, difficulty, and size.' },
82-
{ p: '/v1/q/zec/height', d: 'Single-fact: current Zcash chain height + verification progress + best block hash. Sourced from a live Seneschal-operated zebra node.' },
83-
{ p: '/v1/q/zec/mempool', d: 'Single-fact: Zcash mempool count + bytes.' },
84-
{ p: '/v1/q/zec/last-block', d: 'Single-fact: timestamp + age of the most recent Zcash block, plus hash, difficulty, and size.' }
85-
].map(r => Object.freeze({
86-
method: 'GET',
87-
path: r.p,
88-
description: r.d,
89-
mimeType: 'application/json',
90-
priceEnvKey: 'X402_Q_PRICE'
91-
})),
92-
// Private watch — paywalled creation + credit top-up + historical
93-
// lookup. The watch itself runs on a credit meter (per-day +
94-
// per-call rates set in private-watch.js); each route below
95-
// settles the x402 fee then either creates a row or applies a
96-
// credit increment to an existing row. Routes are explicit per
97-
// price tier because @x402/fastify matches "METHOD /path"
98-
// exactly — no path params, no query-based pricing.
55+
// === Private Watch — Monero/Zcash view-key payment webhooks ===
56+
// The lead product: a paid create, credit-meter top-ups, and a
57+
// one-off historical scan. The watch runs on a credit meter
58+
// (per-day + per-call rates set in private-watch.js); each route
59+
// settles the x402 fee then creates a row or applies a credit
60+
// increment. Explicit per price tier (no path params).
9961
Object.freeze({
10062
method: 'POST',
10163
path: '/v1/private/watch',
@@ -130,10 +92,48 @@ export const PREMIUM_ROUTES = Object.freeze([
13092
description: 'One-off historical scan of a Zcash UFVK or Monero address+viewKey. Returns spendable + spent note totals and (optional) per-note breakdown. The view key streams to NFPT in-memory only — nothing is persisted to our DB. Body: { chain, address, viewKey, birthdayHeight?, toHeight?, includeNotes? }.',
13193
mimeType: 'application/json',
13294
priceEnvKey: 'X402_PRIVATE_HISTORICAL_PRICE'
133-
})
95+
}),
13496
// POST /v1/private/derive-viewkey is intentionally FREE — it's
13597
// rate-limited per-IP at the handler level. Excluded from
13698
// PREMIUM_ROUTES so x402 doesn't try to gate it.
99+
100+
// === Privacy-chain atomic facts (Monero/Zcash) ===
101+
// Sourced from our co-located monerod + zebra full nodes; the
102+
// equivalent thing you'd otherwise need to run yourself (~108 GB
103+
// Monero, ~270 GB Zcash). Cached 10 s server-side so a hot agent
104+
// loop costs the daemon zero extra work.
105+
qFact('/v1/q/xmr/height', 'Single-fact: current Monero chain height + sync status. Sourced from a live Seneschal-operated monerod node.'),
106+
qFact('/v1/q/xmr/mempool', 'Single-fact: number of pending transactions in the Monero mempool right now.'),
107+
qFact('/v1/q/xmr/fee', 'Single-fact: recommended Monero per-byte fee in piconero (also exposed per-kB for convenience).'),
108+
qFact('/v1/q/xmr/last-block', 'Single-fact: timestamp + age of the most recent Monero block, plus hash, difficulty, and size.'),
109+
qFact('/v1/q/zec/height', 'Single-fact: current Zcash chain height + verification progress + best block hash. Sourced from a live Seneschal-operated zebra node.'),
110+
qFact('/v1/q/zec/mempool', 'Single-fact: Zcash mempool count + bytes.'),
111+
qFact('/v1/q/zec/last-block', 'Single-fact: timestamp + age of the most recent Zcash block, plus hash, difficulty, and size.'),
112+
113+
// === DeFi liquidation + Ethereum builder feeds ===
114+
Object.freeze({
115+
method: 'GET',
116+
path: '/v1/premium/opportunities',
117+
description: 'Top at-risk borrowers across Aave + Morpho + Spark with realised market success-rate, average actual profit-USD, and the builder most likely to land each market. Sorted by expected EV. Pure SQL, no live RPC.',
118+
mimeType: 'application/json',
119+
priceEnvKey: 'X402_FEED_PRICE'
120+
}),
121+
Object.freeze({
122+
method: 'GET',
123+
path: '/v1/premium/builder-stats',
124+
description: 'Per-builder bid distribution (p25/median/p75/p90/p99/max) and hourly slot activity histogram from the Seneschal shadow recorder. Answers "what bid value do I need to land in builder X right now?" for searchers tuning bundle pricing.',
125+
mimeType: 'application/json',
126+
priceEnvKey: 'X402_BUILDER_STATS_PRICE'
127+
}),
128+
// === DeFi / builder atomic facts ===
129+
qFact('/v1/q/liquidatable', 'Single-fact: is borrower X currently liquidatable? Returns {found, liquidatable, hf, debt_usd, last_seen_ms} sourced from Aave + Morpho snapshots.'),
130+
qFact('/v1/q/at-risk-count', 'Single-fact: how many borrowers have HF < max_hf and debt >= min_debt_usd right now? Returns {count, total_debt_usd}.'),
131+
qFact('/v1/q/recent-liquidations', 'Single-fact: how many on-chain liquidations have we observed in the last `since_min` minutes, with what aggregate debt? Returns {count, total_debt_usd}.'),
132+
qFact('/v1/q/top-builder', 'Single-fact: which builder has the largest slot share in the named window (24h|7d|30d)? Returns {builder, share_pct, slots_won}.'),
133+
qFact('/v1/q/builder-share', 'Single-fact: what share of slots in the window did `builder` win? Substring match.'),
134+
qFact('/v1/q/builder-bid', 'Single-fact: percentile bid value (in ETH) for `builder` over the window. Returns {value_eth, samples}.'),
135+
qFact('/v1/q/cheapest-flashloan', 'Single-fact: cheapest flash-loan provider for `asset` on `chain` (default ethereum). Returns {provider, fee_bps, address}.'),
136+
qFact('/v1/q/data-freshness', 'Single-fact: age in seconds of the freshest record in the named source (shadow_blocks|borrower_snapshot|morpho_borrower_snapshot|missed_liquidations|executions).')
137137
]);
138138

139139
/**

test/x402.test.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ describe('buildX402Config', () => {
7171
expect(cfg.facilitatorUrl).toBe('https://x402.org/facilitator');
7272
const routeKeys = Object.keys(cfg.routes);
7373
expect(routeKeys.length).toBe(PREMIUM_ROUTES.length);
74-
expect(routeKeys[0]).toBe('GET /v1/premium/opportunities');
74+
// Lead route is the Private Watch product (privacy-coin first).
75+
expect(routeKeys[0]).toBe('POST /v1/private/watch');
7576
const r = cfg.routes['GET /v1/premium/opportunities'];
7677
expect(r.accepts.scheme).toBe('exact');
7778
expect(r.accepts.payTo).toBe(PAY_TO);
@@ -165,7 +166,8 @@ describe('describePaywall', () => {
165166
expect(desc.scheme).toMatch(/EIP-3009/);
166167
expect(desc.routes.length).toBe(PREMIUM_ROUTES.length);
167168
const route = desc.routes[0];
168-
expect(route.endpoint).toBe('GET /v1/premium/opportunities');
169+
// Privacy-coin lead route heads the agent-facing discovery doc.
170+
expect(route.endpoint).toBe('POST /v1/private/watch');
169171
expect(route.price).toBe('$0.05');
170172
expect(route.mime_type).toBe('application/json');
171173
expect(typeof route.description).toBe('string');

0 commit comments

Comments
 (0)