@piprail/sdk 1.11.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,23 @@ 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
+
7
24
  ## [1.11.0] — 2026-06-09
8
25
 
9
26
  ### Added — Agent-friendly discovery lifecycle
@@ -576,6 +593,7 @@ straight into your wallet. The API is small and self-contained.
576
593
  to your wallet; PipRail never holds funds.
577
594
  - `viem ^2.21` is a peer dependency. Node 20+ or a modern browser.
578
595
 
596
+ [1.12.0]: https://www.npmjs.com/package/@piprail/sdk
579
597
  [1.11.0]: https://www.npmjs.com/package/@piprail/sdk
580
598
  [1.10.0]: https://www.npmjs.com/package/@piprail/sdk
581
599
  [1.9.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
@@ -1344,6 +1344,8 @@ function decorateOutcome(o) {
1344
1344
  var BAZAAR_URL = "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources";
1345
1345
  var INDEX402_SEARCH = "https://402index.io/api/v1/services";
1346
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";
1347
1349
  var X402SCAN_REGISTER = "https://www.x402scan.com/api/x402/registry/register";
1348
1350
  var USER_AGENT = "@piprail/sdk (+https://piprail.com)";
1349
1351
  function clientHeaders(extra = {}) {
@@ -1579,6 +1581,53 @@ async function registerX402Scan(input, signer) {
1579
1581
  return { source: "x402scan", ok: false, detail: errMsg(err) };
1580
1582
  }
1581
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
+ }
1582
1631
  async function readSiwxInfo(res) {
1583
1632
  try {
1584
1633
  const body = await res.json();
@@ -2052,6 +2101,32 @@ var PipRailClient = (_class2 = class {
2052
2101
  }
2053
2102
  return outcomes.map(decorateOutcome);
2054
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);
2129
+ }
2055
2130
  /**
2056
2131
  * The discovery signer for the bound wallet (its address + a message signer),
2057
2132
  * or `null` if the chain family doesn't support it (EVM does today). For
@@ -3290,4 +3365,6 @@ function buildX402DnsTxt(input) {
3290
3365
 
3291
3366
 
3292
3367
 
3293
- 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.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;
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;
package/dist/index.d.cts CHANGED
@@ -4365,6 +4365,50 @@ declare function register402Index(input: RegisterInput): Promise<RegisterOutcome
4365
4365
  declare function registerX402Scan(input: {
4366
4366
  url: string;
4367
4367
  }, signer: DiscoverySigner): Promise<RegisterOutcome>;
4368
+ /** What {@link claim402IndexDomain} returns — the proof to SERVE so 402 Index will
4369
+ * approve your domain (and flip your `pending-review` listings to searchable). */
4370
+ interface DomainClaim {
4371
+ ok: boolean;
4372
+ domain: string;
4373
+ /** Serve THIS string as the entire body of `verificationUrl`. */
4374
+ verificationHash?: string;
4375
+ /** Where to serve it — your `https://<domain>/.well-known/402index-verify.txt`. */
4376
+ verificationUrl?: string;
4377
+ /** 402 Index's own human instructions. */
4378
+ instructions?: string;
4379
+ httpStatus?: number;
4380
+ /** Failure reason when `ok:false`. */
4381
+ detail?: string;
4382
+ }
4383
+ /** What {@link verify402IndexDomain} returns once the proof is in place. */
4384
+ interface DomainVerification {
4385
+ ok: boolean;
4386
+ domain: string;
4387
+ /** 402 Index's status string, e.g. `'verified'`. */
4388
+ status?: string;
4389
+ /** How many of your pending listings were approved by the verification. */
4390
+ servicesCount?: number;
4391
+ httpStatus?: number;
4392
+ detail?: string;
4393
+ }
4394
+ /**
4395
+ * Step 1 of 402 Index domain verification: claim the host of `domainOrUrl`. 402 Index
4396
+ * lists a self-registered resource as PENDING REVIEW; verifying the domain approves it
4397
+ * (and every other pending listing on that domain) so it becomes searchable. Returns the
4398
+ * `verificationHash` to serve as the entire body of `verificationUrl`
4399
+ * (`https://<domain>/.well-known/402index-verify.txt`). Then call {@link verify402IndexDomain}.
4400
+ * No funds move. Never throws.
4401
+ */
4402
+ declare function claim402IndexDomain(domainOrUrl: string, opts?: {
4403
+ contactEmail?: string;
4404
+ }): Promise<DomainClaim>;
4405
+ /**
4406
+ * Step 2 of 402 Index domain verification: after {@link claim402IndexDomain} and serving
4407
+ * the `verificationHash` at `verificationUrl`, tell 402 Index to re-fetch + approve. On
4408
+ * success, the domain's pending listings become searchable (`status:'verified'`,
4409
+ * `servicesCount` approved). No funds move. Never throws.
4410
+ */
4411
+ declare function verify402IndexDomain(domainOrUrl: string): Promise<DomainVerification>;
4368
4412
 
4369
4413
  interface PaymentPolicy {
4370
4414
  /** Per-payment ceiling, human-readable (e.g. '0.10'). Compared using the
@@ -4849,6 +4893,30 @@ declare class PipRailClient {
4849
4893
  * on them before calling.
4850
4894
  */
4851
4895
  register(url: string, opts?: RegisterOptions): Promise<RegisterOutcome[]>;
4896
+ /**
4897
+ * **402 Index domain verification, step 1 of 2.** A self-registered 402 Index
4898
+ * listing is `pending-review` (see {@link register}); verifying your domain flips
4899
+ * it — and every other pending listing on that domain — to APPROVED/searchable.
4900
+ * Pass the resource URL or a bare domain; returns the `verificationHash` to serve
4901
+ * as the entire body of `verificationUrl` (your `/.well-known/402index-verify.txt`).
4902
+ * Then serve it and call {@link verifyDomain}. Moves no funds; never throws.
4903
+ *
4904
+ * ```ts
4905
+ * const claim = await client.claimDomain('https://api.example.com/report')
4906
+ * // serve claim.verificationHash at claim.verificationUrl, then:
4907
+ * const res = await client.verifyDomain('api.example.com') // → { ok:true, status:'verified' }
4908
+ * ```
4909
+ */
4910
+ claimDomain(urlOrDomain: string, opts?: {
4911
+ contactEmail?: string;
4912
+ }): Promise<DomainClaim>;
4913
+ /**
4914
+ * **402 Index domain verification, step 2 of 2.** After {@link claimDomain} and
4915
+ * serving the hash at your `/.well-known/402index-verify.txt`, this tells 402 Index
4916
+ * to re-fetch + approve. On success the domain's pending listings become searchable
4917
+ * (`{ ok:true, status:'verified', servicesCount }`). Moves no funds; never throws.
4918
+ */
4919
+ verifyDomain(urlOrDomain: string): Promise<DomainVerification>;
4852
4920
  /**
4853
4921
  * The discovery signer for the bound wallet (its address + a message signer),
4854
4922
  * or `null` if the chain family doesn't support it (EVM does today). For
@@ -5830,4 +5898,4 @@ declare function readExactDomain(publicClient: PublicClient, asset: string): Pro
5830
5898
  version: string;
5831
5899
  } | null>;
5832
5900
 
5833
- export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoverySigner, type DiscoverySource, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, PaymentTimeoutError, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, type XrplToken, buildChallengeHeader, buildExactAuthorization, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, createPaymentGate, decorateOutcome, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, getDirectoryInfo, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, toInsufficientFundsError, toInvalidBody };
5901
+ export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoverySigner, type DiscoverySource, type DomainClaim, type DomainVerification, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, PaymentTimeoutError, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, type XrplToken, buildChallengeHeader, buildExactAuthorization, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, createPaymentGate, decorateOutcome, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, getDirectoryInfo, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };
package/dist/index.d.ts CHANGED
@@ -4365,6 +4365,50 @@ declare function register402Index(input: RegisterInput): Promise<RegisterOutcome
4365
4365
  declare function registerX402Scan(input: {
4366
4366
  url: string;
4367
4367
  }, signer: DiscoverySigner): Promise<RegisterOutcome>;
4368
+ /** What {@link claim402IndexDomain} returns — the proof to SERVE so 402 Index will
4369
+ * approve your domain (and flip your `pending-review` listings to searchable). */
4370
+ interface DomainClaim {
4371
+ ok: boolean;
4372
+ domain: string;
4373
+ /** Serve THIS string as the entire body of `verificationUrl`. */
4374
+ verificationHash?: string;
4375
+ /** Where to serve it — your `https://<domain>/.well-known/402index-verify.txt`. */
4376
+ verificationUrl?: string;
4377
+ /** 402 Index's own human instructions. */
4378
+ instructions?: string;
4379
+ httpStatus?: number;
4380
+ /** Failure reason when `ok:false`. */
4381
+ detail?: string;
4382
+ }
4383
+ /** What {@link verify402IndexDomain} returns once the proof is in place. */
4384
+ interface DomainVerification {
4385
+ ok: boolean;
4386
+ domain: string;
4387
+ /** 402 Index's status string, e.g. `'verified'`. */
4388
+ status?: string;
4389
+ /** How many of your pending listings were approved by the verification. */
4390
+ servicesCount?: number;
4391
+ httpStatus?: number;
4392
+ detail?: string;
4393
+ }
4394
+ /**
4395
+ * Step 1 of 402 Index domain verification: claim the host of `domainOrUrl`. 402 Index
4396
+ * lists a self-registered resource as PENDING REVIEW; verifying the domain approves it
4397
+ * (and every other pending listing on that domain) so it becomes searchable. Returns the
4398
+ * `verificationHash` to serve as the entire body of `verificationUrl`
4399
+ * (`https://<domain>/.well-known/402index-verify.txt`). Then call {@link verify402IndexDomain}.
4400
+ * No funds move. Never throws.
4401
+ */
4402
+ declare function claim402IndexDomain(domainOrUrl: string, opts?: {
4403
+ contactEmail?: string;
4404
+ }): Promise<DomainClaim>;
4405
+ /**
4406
+ * Step 2 of 402 Index domain verification: after {@link claim402IndexDomain} and serving
4407
+ * the `verificationHash` at `verificationUrl`, tell 402 Index to re-fetch + approve. On
4408
+ * success, the domain's pending listings become searchable (`status:'verified'`,
4409
+ * `servicesCount` approved). No funds move. Never throws.
4410
+ */
4411
+ declare function verify402IndexDomain(domainOrUrl: string): Promise<DomainVerification>;
4368
4412
 
4369
4413
  interface PaymentPolicy {
4370
4414
  /** Per-payment ceiling, human-readable (e.g. '0.10'). Compared using the
@@ -4849,6 +4893,30 @@ declare class PipRailClient {
4849
4893
  * on them before calling.
4850
4894
  */
4851
4895
  register(url: string, opts?: RegisterOptions): Promise<RegisterOutcome[]>;
4896
+ /**
4897
+ * **402 Index domain verification, step 1 of 2.** A self-registered 402 Index
4898
+ * listing is `pending-review` (see {@link register}); verifying your domain flips
4899
+ * it — and every other pending listing on that domain — to APPROVED/searchable.
4900
+ * Pass the resource URL or a bare domain; returns the `verificationHash` to serve
4901
+ * as the entire body of `verificationUrl` (your `/.well-known/402index-verify.txt`).
4902
+ * Then serve it and call {@link verifyDomain}. Moves no funds; never throws.
4903
+ *
4904
+ * ```ts
4905
+ * const claim = await client.claimDomain('https://api.example.com/report')
4906
+ * // serve claim.verificationHash at claim.verificationUrl, then:
4907
+ * const res = await client.verifyDomain('api.example.com') // → { ok:true, status:'verified' }
4908
+ * ```
4909
+ */
4910
+ claimDomain(urlOrDomain: string, opts?: {
4911
+ contactEmail?: string;
4912
+ }): Promise<DomainClaim>;
4913
+ /**
4914
+ * **402 Index domain verification, step 2 of 2.** After {@link claimDomain} and
4915
+ * serving the hash at your `/.well-known/402index-verify.txt`, this tells 402 Index
4916
+ * to re-fetch + approve. On success the domain's pending listings become searchable
4917
+ * (`{ ok:true, status:'verified', servicesCount }`). Moves no funds; never throws.
4918
+ */
4919
+ verifyDomain(urlOrDomain: string): Promise<DomainVerification>;
4852
4920
  /**
4853
4921
  * The discovery signer for the bound wallet (its address + a message signer),
4854
4922
  * or `null` if the chain family doesn't support it (EVM does today). For
@@ -5830,4 +5898,4 @@ declare function readExactDomain(publicClient: PublicClient, asset: string): Pro
5830
5898
  version: string;
5831
5899
  } | null>;
5832
5900
 
5833
- export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoverySigner, type DiscoverySource, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, PaymentTimeoutError, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, type XrplToken, buildChallengeHeader, buildExactAuthorization, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, createPaymentGate, decorateOutcome, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, getDirectoryInfo, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, toInsufficientFundsError, toInvalidBody };
5901
+ export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoverySigner, type DiscoverySource, type DomainClaim, type DomainVerification, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, PaymentTimeoutError, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, type XrplToken, buildChallengeHeader, buildExactAuthorization, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, createPaymentGate, decorateOutcome, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, getDirectoryInfo, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };
package/dist/index.js CHANGED
@@ -1344,6 +1344,8 @@ function decorateOutcome(o) {
1344
1344
  var BAZAAR_URL = "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources";
1345
1345
  var INDEX402_SEARCH = "https://402index.io/api/v1/services";
1346
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";
1347
1349
  var X402SCAN_REGISTER = "https://www.x402scan.com/api/x402/registry/register";
1348
1350
  var USER_AGENT = "@piprail/sdk (+https://piprail.com)";
1349
1351
  function clientHeaders(extra = {}) {
@@ -1579,6 +1581,53 @@ async function registerX402Scan(input, signer) {
1579
1581
  return { source: "x402scan", ok: false, detail: errMsg(err) };
1580
1582
  }
1581
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: 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: 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
+ }
1582
1631
  async function readSiwxInfo(res) {
1583
1632
  try {
1584
1633
  const body = await res.json();
@@ -2052,6 +2101,32 @@ var PipRailClient = class {
2052
2101
  }
2053
2102
  return outcomes.map(decorateOutcome);
2054
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);
2129
+ }
2055
2130
  /**
2056
2131
  * The discovery signer for the bound wallet (its address + a message signer),
2057
2132
  * or `null` if the chain family doesn't support it (EVM does today). For
@@ -3265,6 +3340,7 @@ export {
3265
3340
  buildWellKnownX402,
3266
3341
  buildX402DnsTxt,
3267
3342
  chainIdForExactNetwork,
3343
+ claim402IndexDomain,
3268
3344
  createPaymentGate,
3269
3345
  decorateOutcome,
3270
3346
  eip3009Abi,
@@ -3289,5 +3365,6 @@ export {
3289
3365
  searchOpenIndexes,
3290
3366
  settleViaFacilitator,
3291
3367
  toInsufficientFundsError,
3292
- toInvalidBody
3368
+ toInvalidBody,
3369
+ verify402IndexDomain
3293
3370
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piprail/sdk",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "Accept x402 crypto payments across 29 chains — every major EVM chain plus Solana, TON, Tron, NEAR, Sui, Aptos, Algorand, Stellar & XRPL — in a couple of lines. No backend, no database, no fee; payments settle straight to your wallet.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",