@piprail/sdk 1.10.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,50 @@ All notable changes to `@piprail/sdk` are documented here. The format
4
4
  follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
5
5
  versions follow [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [1.12.0] — 2026-06-09
8
+
9
+ ### Added — One-call domain verification (pending-review → searchable)
10
+ - **`client.verifyDomain()` takes a 402 Index listing all the way to searchable.** A self-registered
11
+ 402 Index listing is `pending-review`; verifying the domain you control approves it (and every other
12
+ pending listing on it). `client.claimDomain(urlOrDomain, { contactEmail? })` returns the
13
+ `verificationHash` to serve at your `/.well-known/402index-verify.txt`; `client.verifyDomain(urlOrDomain)`
14
+ then flips it live. Standalone forms `claim402IndexDomain` / `verify402IndexDomain` + the
15
+ `DomainClaim` / `DomainVerification` types are exported. Never throws; moves no funds.
16
+
17
+ ### Docs — a complete, agent-followable discovery playbook
18
+ - Rewrote the **"Be discoverable"** README section into a top-to-bottom **4-step playbook** an agent can
19
+ follow (list → verify domain → discover → self-describe), with the corrected lifecycle output
20
+ (`visibility` + `note`), a `DIRECTORY_INFO` reference table, and the caveats inline (402 Index is
21
+ pending-review; `discover()` doesn't read x402scan; x402scan needs an input schema). Updated
22
+ `llms-full.txt` to the same four moves (EMIT · REGISTER · VERIFY · DISCOVER).
23
+
24
+ ## [1.11.0] — 2026-06-09
25
+
26
+ ### Added — Agent-friendly discovery lifecycle
27
+ - **`register()` outcomes now tell an agent when/where a listing is findable.** Each
28
+ `RegisterOutcome` carries a `visibility: 'live' | 'pending-review' | 'not-listable'` plus a
29
+ plain-language `note` — projected from a new exported source-of-truth, **`DIRECTORY_INFO`**
30
+ (per-index: review mode, auth, chains, `readByDiscover`, caveat). So an agent reads the caveat
31
+ right where it already is instead of guessing. New exports: `DIRECTORY_INFO`, `getDirectoryInfo`,
32
+ `decorateOutcome`, and the `DirectoryInfo` / `ListingVisibility` types.
33
+ - **The sharp caveats are now explicit** (in the types, the `note`, and `register()`/`discover()`
34
+ JSDoc): **402 Index lists a self-registered resource as `pending-review`** (not searchable until
35
+ approved — verify your domain on 402index.io for instant approval), **`discover()` does NOT read
36
+ x402scan** (a live x402scan listing won't appear there — don't read its absence as failure), and
37
+ **CDP Bazaar can't list a backendless PipRail resource at all** (facilitator-coupled).
38
+
39
+ ### Docs — x402 v1/v2 version posture made authoritative
40
+ - A definitive comment in `x402.ts` documents the stance: **emit strict v2, accept liberal v1 + v2**
41
+ (Postel). v2 *replaced* v1 on the wire; the current reference client `@x402/fetch` is v2, but the
42
+ original `x402-fetch`/`x402-express`/`x402-next` packages still send v1, so the gate keeps accepting
43
+ it. PipRail emits no v1 *body* on its own paths; the lone v1 emitter is the `encodeXPaymentHeader`
44
+ utility (its `x402Version: 1` default is correct — consistent with the v1-flat shape it builds).
45
+
46
+ ### Fixed
47
+ - Corrected stale "searchable within seconds" wording for 402 Index (it added a review queue):
48
+ `register402Index`'s success `detail` now surfaces the index's own message, and the JSDoc + MCP
49
+ `piprail_register` tool description reflect the `pending-review` reality.
50
+
7
51
  ## [1.10.0] — 2026-06-09
8
52
 
9
53
  ### Added — Universal Payments (the standard x402 `exact` rail)
@@ -549,6 +593,8 @@ straight into your wallet. The API is small and self-contained.
549
593
  to your wallet; PipRail never holds funds.
550
594
  - `viem ^2.21` is a peer dependency. Node 20+ or a modern browser.
551
595
 
596
+ [1.12.0]: https://www.npmjs.com/package/@piprail/sdk
597
+ [1.11.0]: https://www.npmjs.com/package/@piprail/sdk
552
598
  [1.10.0]: https://www.npmjs.com/package/@piprail/sdk
553
599
  [1.9.0]: https://www.npmjs.com/package/@piprail/sdk
554
600
  [1.8.0]: https://www.npmjs.com/package/@piprail/sdk
package/README.md CHANGED
@@ -148,24 +148,38 @@ See [`examples/agent-tools.mjs`](../examples/agent-tools.mjs) for MCP / AI-SDK w
148
148
  A 402 endpoint is payable, but nobody can *find* it. PipRail closes that gap by building on the
149
149
  **open** x402 indexes that already exist (402 Index, the CDP Bazaar read API, x402scan) — **nothing
150
150
  PipRail-hosted, no registry, no database.** All opt-in; the pay path is untouched. There's **no PipRail
151
- account and no x402 sign-up anywhere** — the only thing ever registered is a merchant's own URL, by one
152
- call. The complete reference including a **step-by-step walkthrough of exactly what each step needs**
153
- (wallet? signing? sign-up? spoiler: 402 Index needs none) is **[DISCOVERY.md](./DISCOVERY.md)** (§7).
151
+ account and no x402 sign-up anywhere** — the only thing ever registered is a merchant's own URL.
152
+ **The four steps below are the whole playbook** an agent can follow them top to bottom (every method
153
+ never throws and returns a typed result that says what to do next); [DISCOVERY.md](./DISCOVERY.md) is
154
+ the deep reference.
154
155
 
155
156
  > **Experimental.** Discovery integrates with third-party open indexes whose conventions are young
156
157
  > and moving — treat this layer as experimental. The read path + 402 Index register are live-verified;
157
158
  > x402scan SIWX isn't yet. Note **402 Index probes your URL and only lists endpoints that actually
158
159
  > return a `402`** — so register a *deployed* gate, not a marketing page. (DISCOVERY.md §10 has the log.)
159
160
 
160
- **1) List a resource you run** — one call, no auth, no signature:
161
+ **1) List a resource you run** — one call, no auth, no signature, no funds:
161
162
 
162
163
  ```ts
163
164
  const client = new PipRailClient({ wallet: { privateKey: KEY }, chain: 'base' })
164
165
 
165
- await client.register('https://api.example.com/report', { name: 'Market Report', priceUsd: 0.05 })
166
- // → [{ source: '402index', ok: true, detail: 'Listed on 402 Index (searchable at 402index.io).' }]
167
- // Add targets: ['402index', 'x402scan'] to also register on x402scan via one wallet signature
168
- // (SIWX — Base/Solana only). It moves no funds; you're listing on third-party open directories.
166
+ const outcomes = await client.register('https://api.example.com/report', {
167
+ name: 'Market Report', priceUsd: 0.05, asset: 'USDC',
168
+ targets: ['402index', 'x402scan'], // 402index is the default; x402scan adds SIWX (Base/Solana)
169
+ })
170
+ // Each outcome carries its LIFECYCLE — read `visibility` + `note`. "ok:true" ≠ "searchable now":
171
+ // • 402index → { ok:true, visibility:'pending-review', note:'… verify your domain for instant approval' }
172
+ // • x402scan → { ok:true, visibility:'live', note:"… discover() does NOT read x402scan" }
173
+ ```
174
+
175
+ **2) Flip 402 Index `pending-review` → searchable** — verify the domain you control (no funds, no sign-up):
176
+
177
+ ```ts
178
+ const claim = await client.claimDomain('https://api.example.com/report', { contactEmail: 'you@example.com' })
179
+ // Serve claim.verificationHash as the ENTIRE body of claim.verificationUrl
180
+ // (https://api.example.com/.well-known/402index-verify.txt) — then:
181
+ await client.verifyDomain('api.example.com') // → { ok:true, status:'verified', servicesCount }
182
+ // Now every pending listing on that domain is approved + searchable.
169
183
  ```
170
184
 
171
185
  **Works on every chain.** 402 Index needs no signature and has no chain allowlist, so *any* chain —
@@ -179,7 +193,7 @@ request sends a `User-Agent: @piprail/sdk` — so the tech spreads through the f
179
193
  the logs operators read, never by spamming listings. An opt-in `register(url, { attribution: true })`
180
194
  adds a best-effort `via` tag; it's off by default (it's your listing).
181
195
 
182
- **2) Find resources to pay** — read the open indexes (free), filtered to your chain by default:
196
+ **3) Find resources to pay** — read the open indexes (free), filtered to your chain by default:
183
197
 
184
198
  ```ts
185
199
  const hits = await client.discover({ query: 'weather', maxPrice: 0.01 })
@@ -187,25 +201,39 @@ const hits = await client.discover({ query: 'weather', maxPrice: 0.01 })
187
201
  const res = await client.fetch(hits[0].resource) // then quote → plan → pay as usual
188
202
  ```
189
203
 
190
- `network` defaults to `'self'` (your chain only); pass `'any'` to search every chain, or a CAIP-2 id
191
- (`'eip155:8453'`) for a specific one. Chain slugs map to CAIP-2 through the `SLUG_TO_CAIP2` table —
192
- adding a chain adds one entry there (see [DISCOVERY.md](./DISCOVERY.md) §2.5), and an unresolved
193
- network is kept, never hidden.
204
+ `discover()` reads **402 Index + CDP Bazaar**, **not x402scan** (its reads are paid) a live x402scan
205
+ listing won't appear here, so don't read that absence as failure. `network` defaults to `'self'` (your
206
+ chain); pass `'any'` for every chain, or a CAIP-2 id (`'eip155:8453'`). Slugs map to CAIP-2 via
207
+ `SLUG_TO_CAIP2`; an unresolved network is kept, never hidden.
194
208
 
195
- **3) Emit a discovery file** — turn your gate's config into the artifacts a crawler reads (pure, no
196
- I/O); serve the result as a static file on **your own** origin:
209
+ **4) Make your endpoint self-describing** — turn your gate's config into the artifacts a crawler reads
210
+ (pure, no I/O); serve them on **your own** origin. **x402scan REQUIRES** a resolvable input schema (your
211
+ `/openapi.json` or an `extensions.bazaar` block in the 402 body), so this is what makes an x402scan
212
+ listing accepted:
197
213
 
198
214
  ```ts
199
- import { createPaymentGate, buildOpenApi, buildX402DnsTxt } from '@piprail/sdk'
215
+ import { createPaymentGate, buildOpenApi, buildWellKnownX402, buildX402DnsTxt } from '@piprail/sdk'
200
216
 
201
217
  const gate = createPaymentGate({ chain: 'base', token: 'USDC', amount: '0.05', payTo })
202
- const openapi = buildOpenApi({
203
- origin: 'https://api.example.com',
204
- resources: [await gate.describe('https://api.example.com/report')],
205
- })
206
- // serve `openapi` at https://api.example.com/openapi.json each priced op carries an `x-payment-info`
207
- // block (the field indexes crawl) plus a default root `x-generator` attribution stamp.
208
- // buildWellKnownX402(...) emits the legacy /.well-known/x402 file; buildX402DnsTxt(...) the _x402 DNS line
218
+ const desc = await gate.describe('https://api.example.com/report')
219
+ const openapi = buildOpenApi({ origin: 'https://api.example.com', resources: [desc] })
220
+ // serve at /openapi.json — each priced op carries an `x-payment-info` block + a root `x-generator` stamp.
221
+ const wellKnown = buildWellKnownX402({ resources: [desc] }) // serve at /.well-known/x402
222
+ // buildX402DnsTxt(...) emits the _x402 DNS line too.
223
+ ```
224
+
225
+ **Know each index before you call** — the facts are one import, `DIRECTORY_INFO`, and `register()`
226
+ projects them onto every outcome (`visibility` + `note`), so an agent never has to guess:
227
+
228
+ | Index | Write auth | Chains | On a successful register | Read by `discover()`? |
229
+ |---|---|---|---|---|
230
+ | **402 Index** (default) | none | any | `pending-review` → `verifyDomain()` for instant approval | ✅ yes |
231
+ | **x402scan** | one wallet sig (SIWX) | Base / Solana | `live` on x402scan.com | ❌ no (paid reads) |
232
+ | **CDP Bazaar** | — (facilitator-only) | — | `not-listable` for PipRail (backendless) | ✅ read-only |
233
+
234
+ ```ts
235
+ import { DIRECTORY_INFO } from '@piprail/sdk'
236
+ DIRECTORY_INFO['x402scan'].readByDiscover // false — branch on this, don't guess
209
237
  ```
210
238
 
211
239
  For an LLM/MCP these are two more tools — **`piprail_discover`** (find) and **`piprail_register`**
package/dist/index.cjs CHANGED
@@ -1305,9 +1305,47 @@ async function resolveNetwork2(opts) {
1305
1305
  }
1306
1306
 
1307
1307
  // src/indexes.ts
1308
+ var DIRECTORY_INFO = {
1309
+ "402index": {
1310
+ source: "402index",
1311
+ review: "probe-sync",
1312
+ auth: "none",
1313
+ chains: null,
1314
+ onSuccess: "pending-review",
1315
+ readByDiscover: true,
1316
+ caveat: "402 Index probes your URL on submit, then lists it as PENDING REVIEW \u2014 a self-registered resource is NOT in search until approved. Verify your domain on 402index.io for instant approval; otherwise it appears after manual review, so retry discover() later."
1317
+ },
1318
+ x402scan: {
1319
+ source: "x402scan",
1320
+ review: "probe-sync",
1321
+ auth: "siwx",
1322
+ chains: ["eip155:8453", "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"],
1323
+ onSuccess: "live",
1324
+ readByDiscover: false,
1325
+ caveat: "x402scan lists Base/Solana only, needs one wallet signature (SIWX), and requires a resolvable input schema (from /openapi.json or the bazaar extension in the 402 body). It goes live on x402scan.com immediately on success \u2014 but discover() does NOT read x402scan, so the listing won't appear in discover() results."
1326
+ },
1327
+ bazaar: {
1328
+ source: "bazaar",
1329
+ review: "settle-coupled",
1330
+ auth: "facilitator-only",
1331
+ chains: null,
1332
+ onSuccess: "not-listable",
1333
+ readByDiscover: true,
1334
+ caveat: "CDP Bazaar has no register endpoint \u2014 it catalogs a resource only when its own facilitator settles a payment. PipRail verifies locally with no facilitator, so a PipRail resource cannot be listed here (you can still READ Bazaar to find others). List on 402 Index or x402scan instead."
1335
+ }
1336
+ };
1337
+ function getDirectoryInfo(source) {
1338
+ return DIRECTORY_INFO[source];
1339
+ }
1340
+ function decorateOutcome(o) {
1341
+ const info = DIRECTORY_INFO[o.source];
1342
+ return { ...o, visibility: o.ok ? info.onSuccess : "not-listable", note: info.caveat };
1343
+ }
1308
1344
  var BAZAAR_URL = "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources";
1309
1345
  var INDEX402_SEARCH = "https://402index.io/api/v1/services";
1310
1346
  var INDEX402_REGISTER = "https://402index.io/api/v1/register";
1347
+ var INDEX402_CLAIM = "https://402index.io/api/v1/claim";
1348
+ var INDEX402_VERIFY = "https://402index.io/api/v1/claim/verify";
1311
1349
  var X402SCAN_REGISTER = "https://www.x402scan.com/api/x402/registry/register";
1312
1350
  var USER_AGENT = "@piprail/sdk (+https://piprail.com)";
1313
1351
  function clientHeaders(extra = {}) {
@@ -1457,7 +1495,13 @@ async function register402Index(input) {
1457
1495
  body: JSON.stringify(payload)
1458
1496
  });
1459
1497
  if (res.ok) {
1460
- return { source: "402index", ok: true, status: res.status, detail: "Listed on 402 Index (searchable at 402index.io)." };
1498
+ const msg = await readIndexMessage(res);
1499
+ return {
1500
+ source: "402index",
1501
+ ok: true,
1502
+ status: res.status,
1503
+ detail: _nullishCoalesce(msg, () => ( "Registered on 402 Index \u2014 pending review (verify your domain on 402index.io for instant approval)."))
1504
+ };
1461
1505
  }
1462
1506
  const why = await readIndexError(res);
1463
1507
  return {
@@ -1470,6 +1514,14 @@ async function register402Index(input) {
1470
1514
  return { source: "402index", ok: false, detail: errMsg(err) };
1471
1515
  }
1472
1516
  }
1517
+ async function readIndexMessage(res) {
1518
+ try {
1519
+ const body = await res.json();
1520
+ return typeof body.message === "string" && body.message.length > 0 ? body.message : void 0;
1521
+ } catch (e17) {
1522
+ return void 0;
1523
+ }
1524
+ }
1473
1525
  async function readIndexError(res) {
1474
1526
  try {
1475
1527
  const body = await res.json();
@@ -1477,7 +1529,7 @@ async function readIndexError(res) {
1477
1529
  (p) => typeof p === "string" && p.length > 0
1478
1530
  );
1479
1531
  return parts.length ? [...new Set(parts)].join(" \u2014 ") : void 0;
1480
- } catch (e17) {
1532
+ } catch (e18) {
1481
1533
  return void 0;
1482
1534
  }
1483
1535
  }
@@ -1529,6 +1581,53 @@ async function registerX402Scan(input, signer) {
1529
1581
  return { source: "x402scan", ok: false, detail: errMsg(err) };
1530
1582
  }
1531
1583
  }
1584
+ async function claim402IndexDomain(domainOrUrl, opts = {}) {
1585
+ const domain = hostOf(domainOrUrl);
1586
+ try {
1587
+ const res = await fetch(INDEX402_CLAIM, {
1588
+ method: "POST",
1589
+ headers: clientHeaders({ "content-type": "application/json", accept: "application/json" }),
1590
+ body: JSON.stringify({ domain, ...opts.contactEmail ? { contact_email: opts.contactEmail } : {} })
1591
+ });
1592
+ const body = await res.json().catch(() => ({}));
1593
+ if (!res.ok) {
1594
+ return { ok: false, domain, httpStatus: res.status, detail: _nullishCoalesce(pickString(body, "error", "detail", "message"), () => ( `402 Index claim returned HTTP ${res.status}.`)) };
1595
+ }
1596
+ return {
1597
+ ok: true,
1598
+ domain,
1599
+ httpStatus: res.status,
1600
+ ...optionalString("verificationHash", pickString(body, "verification_hash")),
1601
+ ...optionalString("verificationUrl", pickString(body, "verification_url")),
1602
+ ...optionalString("instructions", pickString(body, "instructions"))
1603
+ };
1604
+ } catch (err) {
1605
+ return { ok: false, domain, detail: errMsg(err) };
1606
+ }
1607
+ }
1608
+ async function verify402IndexDomain(domainOrUrl) {
1609
+ const domain = hostOf(domainOrUrl);
1610
+ try {
1611
+ const res = await fetch(INDEX402_VERIFY, {
1612
+ method: "POST",
1613
+ headers: clientHeaders({ "content-type": "application/json", accept: "application/json" }),
1614
+ body: JSON.stringify({ domain })
1615
+ });
1616
+ const body = await res.json().catch(() => ({}));
1617
+ if (!res.ok) {
1618
+ return { ok: false, domain, httpStatus: res.status, detail: _nullishCoalesce(pickString(body, "error", "detail", "message"), () => ( `402 Index verify returned HTTP ${res.status}.`)) };
1619
+ }
1620
+ return {
1621
+ ok: true,
1622
+ domain,
1623
+ httpStatus: res.status,
1624
+ ...optionalString("status", pickString(body, "status")),
1625
+ ...typeof body.services_count === "number" ? { servicesCount: body.services_count } : {}
1626
+ };
1627
+ } catch (err) {
1628
+ return { ok: false, domain, detail: errMsg(err) };
1629
+ }
1630
+ }
1532
1631
  async function readSiwxInfo(res) {
1533
1632
  try {
1534
1633
  const body = await res.json();
@@ -1539,7 +1638,7 @@ async function readSiwxInfo(res) {
1539
1638
  return info;
1540
1639
  }
1541
1640
  return null;
1542
- } catch (e18) {
1641
+ } catch (e19) {
1543
1642
  return null;
1544
1643
  }
1545
1644
  }
@@ -1619,7 +1718,7 @@ function firstArray(o, ...keys) {
1619
1718
  function hostOf(url) {
1620
1719
  try {
1621
1720
  return new URL(url).hostname;
1622
- } catch (e19) {
1721
+ } catch (e20) {
1623
1722
  return url;
1624
1723
  }
1625
1724
  }
@@ -1774,7 +1873,7 @@ var PipRailClient = (_class2 = class {
1774
1873
  safeEmit(event) {
1775
1874
  try {
1776
1875
  this.onEvent(event);
1777
- } catch (e20) {
1876
+ } catch (e21) {
1778
1877
  }
1779
1878
  }
1780
1879
  /** Auto-mount the chain's driver, resolve the network, and bind the wallet — once. */
@@ -1908,9 +2007,15 @@ var PipRailClient = (_class2 = class {
1908
2007
  *
1909
2008
  * Nothing PipRail-hosted: these are third-party open directories. Never throws
1910
2009
  * for a read problem — an index that's down or changed simply contributes
1911
- * nothing. Honest caveat: index results are cross-scheme (mostly the
1912
- * mainstream `exact` scheme); `fetch()` pays only `onchain-proof` rails
1913
- * directly (pay `exact` resources with the experimental `drivers/evm/exact.ts`).
2010
+ * nothing. Honest caveats (see {@link DIRECTORY_INFO}):
2011
+ * - Reads **`bazaar` + `402index`** only — **NOT `x402scan`** (its reads are paid). A
2012
+ * resource you registered on x402scan is live there but will NOT appear here; don't
2013
+ * read that absence as failure. (Passing `sources:['x402scan']` explicitly yields `[]`.)
2014
+ * - A resource just listed via {@link register} may not appear yet — 402 Index reviews
2015
+ * before publishing, so retry with a brief backoff if a fresh listing is missing.
2016
+ * - Results are cross-scheme (mostly the mainstream `exact` scheme); `fetch()` pays
2017
+ * only `onchain-proof` rails directly (pay `exact` resources with the experimental
2018
+ * `drivers/evm/exact.ts`).
1914
2019
  */
1915
2020
  async discover(opts = {}) {
1916
2021
  const found = await searchOpenIndexes({
@@ -1935,12 +2040,27 @@ var PipRailClient = (_class2 = class {
1935
2040
  }
1936
2041
  /**
1937
2042
  * List a resource you run on the OPEN x402 registries, so agents can find it.
1938
- * Default target is **402 Index** — one POST, no auth, no signature, no payment
1939
- * (searchable within seconds). Add `'x402scan'` to also register via SIWX (one
1940
- * wallet signature; EVM + a Base/Solana rail). Returns one {@link RegisterOutcome}
1941
- * per target — a target the chain can't satisfy comes back `{ ok:false, detail }`,
1942
- * never a throw. An explicit, developer-invoked action; it moves no funds, and
1943
- * nothing is PipRail-hosted — you're listing on third-party open directories.
2043
+ * Default target is **402 Index** — one POST, no auth, no signature, no payment.
2044
+ * Add `'x402scan'` to also register via SIWX (one wallet signature; EVM + a
2045
+ * Base/Solana rail). Returns one {@link RegisterOutcome} per target — a target the
2046
+ * chain can't satisfy comes back `{ ok:false, detail }`, never a throw. An explicit,
2047
+ * developer-invoked action; it moves no funds, and nothing is PipRail-hosted —
2048
+ * you're listing on third-party open directories.
2049
+ *
2050
+ * **Listing is asynchronous — each outcome carries a `visibility` + `note` so an
2051
+ * agent knows when/where the resource is findable (don't assume `ok:true` means
2052
+ * "searchable now"):**
2053
+ * - **402 Index** → `visibility:'pending-review'`. It probes your URL on submit, then lists it
2054
+ * PENDING REVIEW — not searchable until approved (verify your domain on 402index.io for instant
2055
+ * approval), so `discover()` returns nothing for a fresh listing until then. Retry later.
2056
+ * - **x402scan** → `visibility:'live'`, but **`discover()` does NOT read x402scan** — the
2057
+ * listing is real on x402scan.com yet won't show up in `discover()`. Base/Solana only;
2058
+ * needs a resolvable input schema (`/openapi.json` or the `extensions.bazaar` block).
2059
+ * - **Bazaar** → `visibility:'not-listable'` for PipRail (it lists only what its facilitator
2060
+ * settles; PipRail uses none). You can still READ Bazaar via {@link discover} to find others.
2061
+ *
2062
+ * The per-source facts live in {@link DIRECTORY_INFO} (importable) if you'd rather branch
2063
+ * on them before calling.
1944
2064
  */
1945
2065
  async register(url, opts = {}) {
1946
2066
  const targets = _nullishCoalesce(opts.targets, () => ( ["402index"]));
@@ -1979,7 +2099,33 @@ var PipRailClient = (_class2 = class {
1979
2099
  });
1980
2100
  }
1981
2101
  }
1982
- return outcomes;
2102
+ return outcomes.map(decorateOutcome);
2103
+ }
2104
+ /**
2105
+ * **402 Index domain verification, step 1 of 2.** A self-registered 402 Index
2106
+ * listing is `pending-review` (see {@link register}); verifying your domain flips
2107
+ * it — and every other pending listing on that domain — to APPROVED/searchable.
2108
+ * Pass the resource URL or a bare domain; returns the `verificationHash` to serve
2109
+ * as the entire body of `verificationUrl` (your `/.well-known/402index-verify.txt`).
2110
+ * Then serve it and call {@link verifyDomain}. Moves no funds; never throws.
2111
+ *
2112
+ * ```ts
2113
+ * const claim = await client.claimDomain('https://api.example.com/report')
2114
+ * // serve claim.verificationHash at claim.verificationUrl, then:
2115
+ * const res = await client.verifyDomain('api.example.com') // → { ok:true, status:'verified' }
2116
+ * ```
2117
+ */
2118
+ async claimDomain(urlOrDomain, opts = {}) {
2119
+ return claim402IndexDomain(urlOrDomain, opts);
2120
+ }
2121
+ /**
2122
+ * **402 Index domain verification, step 2 of 2.** After {@link claimDomain} and
2123
+ * serving the hash at your `/.well-known/402index-verify.txt`, this tells 402 Index
2124
+ * to re-fetch + approve. On success the domain's pending listings become searchable
2125
+ * (`{ ok:true, status:'verified', servicesCount }`). Moves no funds; never throws.
2126
+ */
2127
+ async verifyDomain(urlOrDomain) {
2128
+ return verify402IndexDomain(urlOrDomain);
1983
2129
  }
1984
2130
  /**
1985
2131
  * The discovery signer for the bound wallet (its address + a message signer),
@@ -2339,7 +2485,7 @@ var PipRailClient = (_class2 = class {
2339
2485
  function safeBig(s) {
2340
2486
  try {
2341
2487
  return BigInt(s);
2342
- } catch (e21) {
2488
+ } catch (e22) {
2343
2489
  return 0n;
2344
2490
  }
2345
2491
  }
@@ -2405,7 +2551,7 @@ function railOnNetwork(rail, matches) {
2405
2551
  function hostOf2(url) {
2406
2552
  try {
2407
2553
  return new URL(url).hostname;
2408
- } catch (e22) {
2554
+ } catch (e23) {
2409
2555
  return url;
2410
2556
  }
2411
2557
  }
@@ -2436,7 +2582,7 @@ async function readInvalidReason(response) {
2436
2582
  detail: typeof body.detail === "string" ? body.detail : ""
2437
2583
  };
2438
2584
  }
2439
- } catch (e23) {
2585
+ } catch (e24) {
2440
2586
  }
2441
2587
  return null;
2442
2588
  }
@@ -2447,7 +2593,7 @@ async function readBody(res) {
2447
2593
  if (!text) return null;
2448
2594
  try {
2449
2595
  return JSON.parse(text);
2450
- } catch (e24) {
2596
+ } catch (e25) {
2451
2597
  return text;
2452
2598
  }
2453
2599
  }
@@ -2627,7 +2773,7 @@ function paymentTools(client) {
2627
2773
  },
2628
2774
  {
2629
2775
  name: "piprail_register",
2630
- description: "List an x402 payment-gated resource YOU run on the open indexes so other agents can discover it. Default target is 402 Index \u2014 no auth, no signature, no payment; searchable within seconds. Returns one outcome per index ({ source, ok, detail }); a step the chain can't satisfy comes back ok:false with the reason. Moves no funds; nothing is PipRail-hosted.",
2776
+ description: "List an x402 payment-gated resource YOU run on the open indexes so other agents can discover it. Default target is 402 Index \u2014 no auth, no signature, no payment; a self-registered listing is pending review (verify your domain on 402index.io for instant approval). Returns one outcome per index ({ source, ok, detail, visibility, note }); a step the chain can't satisfy comes back ok:false with the reason. Moves no funds; nothing is PipRail-hosted.",
2631
2777
  annotations: {
2632
2778
  title: "Register an x402 endpoint",
2633
2779
  readOnlyHint: false,
@@ -2685,7 +2831,7 @@ async function post(url, body, headers) {
2685
2831
  let json = null;
2686
2832
  try {
2687
2833
  json = await res.json();
2688
- } catch (e25) {
2834
+ } catch (e26) {
2689
2835
  }
2690
2836
  return { status: res.status, json };
2691
2837
  }
@@ -2939,7 +3085,7 @@ function createPaymentGate(options) {
2939
3085
  if (options.onPaid) {
2940
3086
  try {
2941
3087
  options.onPaid(receipt);
2942
- } catch (e26) {
3088
+ } catch (e27) {
2943
3089
  }
2944
3090
  }
2945
3091
  }
@@ -3109,7 +3255,7 @@ var GENERATOR = "@piprail/sdk \xB7 https://piprail.com";
3109
3255
  function pathOf(url) {
3110
3256
  try {
3111
3257
  return new URL(url).pathname || "/";
3112
- } catch (e27) {
3258
+ } catch (e28) {
3113
3259
  return url.startsWith("/") ? url : `/${url}`;
3114
3260
  }
3115
3261
  }
@@ -3216,4 +3362,9 @@ function buildX402DnsTxt(input) {
3216
3362
 
3217
3363
 
3218
3364
 
3219
- exports.CHAINS = CHAINS; exports.ConfirmationTimeoutError = _chunkMDLZJGLYcjs.ConfirmationTimeoutError; exports.EIP3009_TYPES = EIP3009_TYPES; exports.EXACT_NETWORK_SLUGS = EXACT_NETWORK_SLUGS; exports.GENERATOR = GENERATOR; exports.HEADER_REQUIRED = HEADER_REQUIRED; exports.HEADER_RESPONSE = HEADER_RESPONSE; exports.HEADER_RESPONSE_V1 = HEADER_RESPONSE_V1; exports.HEADER_SIGNATURE = HEADER_SIGNATURE; exports.HEADER_SIGNATURE_V1 = HEADER_SIGNATURE_V1; exports.InsufficientFundsError = _chunkMDLZJGLYcjs.InsufficientFundsError; exports.InvalidEnvelopeError = _chunkMDLZJGLYcjs.InvalidEnvelopeError; exports.MaxRetriesExceededError = _chunkMDLZJGLYcjs.MaxRetriesExceededError; exports.MissingDriverError = _chunkMDLZJGLYcjs.MissingDriverError; exports.NoCompatibleAcceptError = _chunkMDLZJGLYcjs.NoCompatibleAcceptError; exports.NonReplayableBodyError = _chunkMDLZJGLYcjs.NonReplayableBodyError; exports.PaymentDeclinedError = _chunkMDLZJGLYcjs.PaymentDeclinedError; exports.PaymentTimeoutError = _chunkMDLZJGLYcjs.PaymentTimeoutError; exports.PipRailClient = PipRailClient; exports.PipRailError = _chunkMDLZJGLYcjs.PipRailError; exports.RecipientNotReadyError = _chunkMDLZJGLYcjs.RecipientNotReadyError; exports.SettlementError = _chunkMDLZJGLYcjs.SettlementError; exports.UnknownTokenError = _chunkMDLZJGLYcjs.UnknownTokenError; exports.UnsupportedNetworkError = _chunkMDLZJGLYcjs.UnsupportedNetworkError; exports.WrongChainError = _chunkMDLZJGLYcjs.WrongChainError; exports.WrongFamilyError = _chunkMDLZJGLYcjs.WrongFamilyError; exports.buildChallengeHeader = buildChallengeHeader; exports.buildExactAuthorization = buildExactAuthorization; exports.buildOpenApi = buildOpenApi; exports.buildReceiptHeader = buildReceiptHeader; exports.buildSignatureHeader = buildSignatureHeader; exports.buildWellKnownX402 = buildWellKnownX402; exports.buildX402DnsTxt = buildX402DnsTxt; exports.chainIdForExactNetwork = chainIdForExactNetwork; exports.createPaymentGate = createPaymentGate; exports.eip3009Abi = eip3009Abi; exports.encodeXPaymentHeader = encodeXPaymentHeader; exports.evaluatePolicy = evaluatePolicy; exports.normalizeNetwork = normalizeNetwork; exports.parseChallenge = parseChallenge; exports.parseExactPaymentHeader = parseExactPaymentHeader; exports.parseExactRequirements = parseExactRequirements; exports.parseReceipt = parseReceipt; exports.parseSignatureHeader = parseSignatureHeader; exports.paymentTools = paymentTools; exports.pickAccept = pickAccept; exports.planAcross = planAcross; exports.readExactDomain = readExactDomain; exports.register402Index = register402Index; exports.registerDriver = registerDriver; exports.registerX402Scan = registerX402Scan; exports.requirePayment = requirePayment; exports.resolveChain = resolveChain; exports.searchOpenIndexes = searchOpenIndexes; exports.settleViaFacilitator = settleViaFacilitator; exports.toInsufficientFundsError = _chunkMDLZJGLYcjs.toInsufficientFundsError; exports.toInvalidBody = toInvalidBody;
3365
+
3366
+
3367
+
3368
+
3369
+
3370
+ exports.CHAINS = CHAINS; exports.ConfirmationTimeoutError = _chunkMDLZJGLYcjs.ConfirmationTimeoutError; exports.DIRECTORY_INFO = DIRECTORY_INFO; exports.EIP3009_TYPES = EIP3009_TYPES; exports.EXACT_NETWORK_SLUGS = EXACT_NETWORK_SLUGS; exports.GENERATOR = GENERATOR; exports.HEADER_REQUIRED = HEADER_REQUIRED; exports.HEADER_RESPONSE = HEADER_RESPONSE; exports.HEADER_RESPONSE_V1 = HEADER_RESPONSE_V1; exports.HEADER_SIGNATURE = HEADER_SIGNATURE; exports.HEADER_SIGNATURE_V1 = HEADER_SIGNATURE_V1; exports.InsufficientFundsError = _chunkMDLZJGLYcjs.InsufficientFundsError; exports.InvalidEnvelopeError = _chunkMDLZJGLYcjs.InvalidEnvelopeError; exports.MaxRetriesExceededError = _chunkMDLZJGLYcjs.MaxRetriesExceededError; exports.MissingDriverError = _chunkMDLZJGLYcjs.MissingDriverError; exports.NoCompatibleAcceptError = _chunkMDLZJGLYcjs.NoCompatibleAcceptError; exports.NonReplayableBodyError = _chunkMDLZJGLYcjs.NonReplayableBodyError; exports.PaymentDeclinedError = _chunkMDLZJGLYcjs.PaymentDeclinedError; exports.PaymentTimeoutError = _chunkMDLZJGLYcjs.PaymentTimeoutError; exports.PipRailClient = PipRailClient; exports.PipRailError = _chunkMDLZJGLYcjs.PipRailError; exports.RecipientNotReadyError = _chunkMDLZJGLYcjs.RecipientNotReadyError; exports.SettlementError = _chunkMDLZJGLYcjs.SettlementError; exports.UnknownTokenError = _chunkMDLZJGLYcjs.UnknownTokenError; exports.UnsupportedNetworkError = _chunkMDLZJGLYcjs.UnsupportedNetworkError; exports.WrongChainError = _chunkMDLZJGLYcjs.WrongChainError; exports.WrongFamilyError = _chunkMDLZJGLYcjs.WrongFamilyError; exports.buildChallengeHeader = buildChallengeHeader; exports.buildExactAuthorization = buildExactAuthorization; exports.buildOpenApi = buildOpenApi; exports.buildReceiptHeader = buildReceiptHeader; exports.buildSignatureHeader = buildSignatureHeader; exports.buildWellKnownX402 = buildWellKnownX402; exports.buildX402DnsTxt = buildX402DnsTxt; exports.chainIdForExactNetwork = chainIdForExactNetwork; exports.claim402IndexDomain = claim402IndexDomain; exports.createPaymentGate = createPaymentGate; exports.decorateOutcome = decorateOutcome; exports.eip3009Abi = eip3009Abi; exports.encodeXPaymentHeader = encodeXPaymentHeader; exports.evaluatePolicy = evaluatePolicy; exports.getDirectoryInfo = getDirectoryInfo; exports.normalizeNetwork = normalizeNetwork; exports.parseChallenge = parseChallenge; exports.parseExactPaymentHeader = parseExactPaymentHeader; exports.parseExactRequirements = parseExactRequirements; exports.parseReceipt = parseReceipt; exports.parseSignatureHeader = parseSignatureHeader; exports.paymentTools = paymentTools; exports.pickAccept = pickAccept; exports.planAcross = planAcross; exports.readExactDomain = readExactDomain; exports.register402Index = register402Index; exports.registerDriver = registerDriver; exports.registerX402Scan = registerX402Scan; exports.requirePayment = requirePayment; exports.resolveChain = resolveChain; exports.searchOpenIndexes = searchOpenIndexes; exports.settleViaFacilitator = settleViaFacilitator; exports.toInsufficientFundsError = _chunkMDLZJGLYcjs.toInsufficientFundsError; exports.toInvalidBody = toInvalidBody; exports.verify402IndexDomain = verify402IndexDomain;