@absol-labs/agent 0.11.0 → 0.12.0-rc.1

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.
Files changed (350) hide show
  1. package/README.md +42 -50
  2. package/dist/capability/invocation-capability.d.ts +2 -2
  3. package/dist/capability/probe-capability.d.ts +225 -0
  4. package/dist/capability/probe-capability.d.ts.map +1 -0
  5. package/dist/capability/probe-capability.js +248 -0
  6. package/dist/capability/probe-capability.js.map +1 -0
  7. package/dist/cli/args.d.ts +11 -0
  8. package/dist/cli/args.d.ts.map +1 -1
  9. package/dist/cli/args.js +23 -0
  10. package/dist/cli/args.js.map +1 -1
  11. package/dist/cli/commands/claim.js +1 -1
  12. package/dist/cli/commands/claim.js.map +1 -1
  13. package/dist/cli/commands/close.d.ts.map +1 -1
  14. package/dist/cli/commands/close.js +35 -3
  15. package/dist/cli/commands/close.js.map +1 -1
  16. package/dist/cli/commands/invoke.d.ts +2 -0
  17. package/dist/cli/commands/invoke.d.ts.map +1 -1
  18. package/dist/cli/commands/invoke.js +2 -2
  19. package/dist/cli/commands/invoke.js.map +1 -1
  20. package/dist/cli/commands/mcp.d.ts.map +1 -1
  21. package/dist/cli/commands/mcp.js +15 -2
  22. package/dist/cli/commands/mcp.js.map +1 -1
  23. package/dist/cli/commands/open.d.ts.map +1 -1
  24. package/dist/cli/commands/open.js +58 -4
  25. package/dist/cli/commands/open.js.map +1 -1
  26. package/dist/cli/commands/pay.d.ts +19 -0
  27. package/dist/cli/commands/pay.d.ts.map +1 -0
  28. package/dist/cli/commands/pay.js +355 -0
  29. package/dist/cli/commands/pay.js.map +1 -0
  30. package/dist/cli/commands/reclaim-unverified.d.ts.map +1 -1
  31. package/dist/cli/commands/reclaim-unverified.js +3 -2
  32. package/dist/cli/commands/reclaim-unverified.js.map +1 -1
  33. package/dist/cli/commands/reclaim.d.ts +23 -2
  34. package/dist/cli/commands/reclaim.d.ts.map +1 -1
  35. package/dist/cli/commands/reclaim.js +184 -16
  36. package/dist/cli/commands/reclaim.js.map +1 -1
  37. package/dist/cli/commands/refund.d.ts +13 -0
  38. package/dist/cli/commands/refund.d.ts.map +1 -0
  39. package/dist/cli/commands/refund.js +224 -0
  40. package/dist/cli/commands/refund.js.map +1 -0
  41. package/dist/cli/commands/status.d.ts.map +1 -1
  42. package/dist/cli/commands/status.js +10 -1
  43. package/dist/cli/commands/status.js.map +1 -1
  44. package/dist/cli/commands/streams.js +8 -12
  45. package/dist/cli/commands/streams.js.map +1 -1
  46. package/dist/cli/commands/watch.d.ts.map +1 -1
  47. package/dist/cli/commands/watch.js +2 -1
  48. package/dist/cli/commands/watch.js.map +1 -1
  49. package/dist/cli/config.d.ts +44 -26
  50. package/dist/cli/config.d.ts.map +1 -1
  51. package/dist/cli/config.js +88 -38
  52. package/dist/cli/config.js.map +1 -1
  53. package/dist/cli/deps.d.ts +33 -0
  54. package/dist/cli/deps.d.ts.map +1 -1
  55. package/dist/cli/deps.js +37 -1
  56. package/dist/cli/deps.js.map +1 -1
  57. package/dist/cli/errors.d.ts.map +1 -1
  58. package/dist/cli/errors.js +21 -1
  59. package/dist/cli/errors.js.map +1 -1
  60. package/dist/cli/escape-hatch.d.ts +6 -4
  61. package/dist/cli/escape-hatch.d.ts.map +1 -1
  62. package/dist/cli/escape-hatch.js +6 -2
  63. package/dist/cli/escape-hatch.js.map +1 -1
  64. package/dist/cli/listings.d.ts +18 -0
  65. package/dist/cli/listings.d.ts.map +1 -1
  66. package/dist/cli/listings.js +22 -12
  67. package/dist/cli/listings.js.map +1 -1
  68. package/dist/cli/preflight.d.ts +20 -14
  69. package/dist/cli/preflight.d.ts.map +1 -1
  70. package/dist/cli/preflight.js +34 -20
  71. package/dist/cli/preflight.js.map +1 -1
  72. package/dist/cli/privy.d.ts.map +1 -1
  73. package/dist/cli/privy.js +4 -2
  74. package/dist/cli/privy.js.map +1 -1
  75. package/dist/cli/reclaimability.d.ts +82 -0
  76. package/dist/cli/reclaimability.d.ts.map +1 -0
  77. package/dist/cli/reclaimability.js +80 -0
  78. package/dist/cli/reclaimability.js.map +1 -0
  79. package/dist/cli/run.d.ts +2 -1
  80. package/dist/cli/run.d.ts.map +1 -1
  81. package/dist/cli/run.js +40 -11
  82. package/dist/cli/run.js.map +1 -1
  83. package/dist/cli/scan-range.d.ts +2 -2
  84. package/dist/cli/scan-range.js +2 -2
  85. package/dist/cli/status.d.ts +3 -1
  86. package/dist/cli/status.d.ts.map +1 -1
  87. package/dist/cli/status.js +15 -3
  88. package/dist/cli/status.js.map +1 -1
  89. package/dist/cli/wallet.d.ts +1 -1
  90. package/dist/cli/wallet.js +2 -2
  91. package/dist/cli/wallet.js.map +1 -1
  92. package/dist/discovery/rate-band.d.ts +74 -0
  93. package/dist/discovery/rate-band.d.ts.map +1 -0
  94. package/dist/discovery/rate-band.js +114 -0
  95. package/dist/discovery/rate-band.js.map +1 -0
  96. package/dist/escrow-generation.d.ts +81 -0
  97. package/dist/escrow-generation.d.ts.map +1 -0
  98. package/dist/escrow-generation.js +76 -0
  99. package/dist/escrow-generation.js.map +1 -0
  100. package/dist/frameworks/agentkit.d.ts +8 -4
  101. package/dist/frameworks/agentkit.d.ts.map +1 -1
  102. package/dist/frameworks/agentkit.js +27 -10
  103. package/dist/frameworks/agentkit.js.map +1 -1
  104. package/dist/frameworks/eliza.d.ts +3 -3
  105. package/dist/frameworks/eliza.d.ts.map +1 -1
  106. package/dist/frameworks/eliza.js +15 -6
  107. package/dist/frameworks/eliza.js.map +1 -1
  108. package/dist/frameworks/langchain.d.ts.map +1 -1
  109. package/dist/frameworks/langchain.js +8 -0
  110. package/dist/frameworks/langchain.js.map +1 -1
  111. package/dist/gateway/caller-auth-gateway.d.ts +83 -31
  112. package/dist/gateway/caller-auth-gateway.d.ts.map +1 -1
  113. package/dist/gateway/caller-auth-gateway.js +180 -27
  114. package/dist/gateway/caller-auth-gateway.js.map +1 -1
  115. package/dist/gateway/http-server.d.ts +111 -44
  116. package/dist/gateway/http-server.d.ts.map +1 -1
  117. package/dist/gateway/http-server.js +439 -155
  118. package/dist/gateway/http-server.js.map +1 -1
  119. package/dist/gateway/probe-auth.d.ts +112 -0
  120. package/dist/gateway/probe-auth.d.ts.map +1 -0
  121. package/dist/gateway/probe-auth.js +127 -0
  122. package/dist/gateway/probe-auth.js.map +1 -0
  123. package/dist/gateway/signed-rate-bounds.d.ts +51 -0
  124. package/dist/gateway/signed-rate-bounds.d.ts.map +1 -0
  125. package/dist/gateway/signed-rate-bounds.js +94 -0
  126. package/dist/gateway/signed-rate-bounds.js.map +1 -0
  127. package/dist/gateway/x402-opener-mode.d.ts +215 -0
  128. package/dist/gateway/x402-opener-mode.d.ts.map +1 -0
  129. package/dist/gateway/x402-opener-mode.js +639 -0
  130. package/dist/gateway/x402-opener-mode.js.map +1 -0
  131. package/dist/index.d.ts +6 -2
  132. package/dist/index.d.ts.map +1 -1
  133. package/dist/index.js +10 -5
  134. package/dist/index.js.map +1 -1
  135. package/dist/mcp/server.d.ts +52 -1
  136. package/dist/mcp/server.d.ts.map +1 -1
  137. package/dist/mcp/server.js +228 -37
  138. package/dist/mcp/server.js.map +1 -1
  139. package/dist/mcp/x402-tools.d.ts +104 -0
  140. package/dist/mcp/x402-tools.d.ts.map +1 -0
  141. package/dist/mcp/x402-tools.js +434 -0
  142. package/dist/mcp/x402-tools.js.map +1 -0
  143. package/dist/network.d.ts +119 -0
  144. package/dist/network.d.ts.map +1 -0
  145. package/dist/network.js +199 -0
  146. package/dist/network.js.map +1 -0
  147. package/dist/sdk/invoke.d.ts +4 -0
  148. package/dist/sdk/invoke.d.ts.map +1 -1
  149. package/dist/sdk/invoke.js +2 -5
  150. package/dist/sdk/invoke.js.map +1 -1
  151. package/dist/wallet/autonomous-wallet-broker.d.ts +3 -0
  152. package/dist/wallet/autonomous-wallet-broker.d.ts.map +1 -1
  153. package/dist/wallet/autonomous-wallet-broker.js +27 -23
  154. package/dist/wallet/autonomous-wallet-broker.js.map +1 -1
  155. package/dist/wallet/autonomous-wallet-protocol.d.ts +8 -2
  156. package/dist/wallet/autonomous-wallet-protocol.d.ts.map +1 -1
  157. package/dist/wallet/autonomous-wallet-protocol.js +9 -2
  158. package/dist/wallet/autonomous-wallet-protocol.js.map +1 -1
  159. package/dist/wallet/autonomous-wallet.d.ts.map +1 -1
  160. package/dist/wallet/autonomous-wallet.js +3 -2
  161. package/dist/wallet/autonomous-wallet.js.map +1 -1
  162. package/dist/wallet/broker-escrows.d.ts +222 -0
  163. package/dist/wallet/broker-escrows.d.ts.map +1 -0
  164. package/dist/wallet/broker-escrows.js +36 -0
  165. package/dist/wallet/broker-escrows.js.map +1 -0
  166. package/dist/wallet/lifecycle.d.ts +21 -5
  167. package/dist/wallet/lifecycle.d.ts.map +1 -1
  168. package/dist/wallet/lifecycle.js +32 -12
  169. package/dist/wallet/lifecycle.js.map +1 -1
  170. package/dist/wallet/privy-broker-server.d.ts.map +1 -1
  171. package/dist/wallet/privy-broker-server.js +31 -26
  172. package/dist/wallet/privy-broker-server.js.map +1 -1
  173. package/dist/wallet/privy-session-broker.d.ts +14 -5
  174. package/dist/wallet/privy-session-broker.d.ts.map +1 -1
  175. package/dist/wallet/privy-session-broker.js +29 -17
  176. package/dist/wallet/privy-session-broker.js.map +1 -1
  177. package/dist/wallet/privy-session-provider.d.ts +3 -1
  178. package/dist/wallet/privy-session-provider.d.ts.map +1 -1
  179. package/dist/wallet/privy-session-provider.js +5 -3
  180. package/dist/wallet/privy-session-provider.js.map +1 -1
  181. package/dist/wallet/provider.d.ts.map +1 -1
  182. package/dist/wallet/provider.js +15 -8
  183. package/dist/wallet/provider.js.map +1 -1
  184. package/dist/x402/facilitator.d.ts +3 -30
  185. package/dist/x402/facilitator.d.ts.map +1 -1
  186. package/dist/x402/facilitator.js +0 -27
  187. package/dist/x402/facilitator.js.map +1 -1
  188. package/dist/x402-buyer/guarded-fetch.d.ts +51 -0
  189. package/dist/x402-buyer/guarded-fetch.d.ts.map +1 -0
  190. package/dist/x402-buyer/guarded-fetch.js +147 -0
  191. package/dist/x402-buyer/guarded-fetch.js.map +1 -0
  192. package/dist/x402-buyer/index.d.ts +10 -0
  193. package/dist/x402-buyer/index.d.ts.map +1 -0
  194. package/dist/x402-buyer/index.js +10 -0
  195. package/dist/x402-buyer/index.js.map +1 -0
  196. package/dist/x402-buyer/pay.d.ts +135 -0
  197. package/dist/x402-buyer/pay.d.ts.map +1 -0
  198. package/dist/x402-buyer/pay.js +336 -0
  199. package/dist/x402-buyer/pay.js.map +1 -0
  200. package/dist/x402-opener/abi.d.ts +684 -0
  201. package/dist/x402-opener/abi.d.ts.map +1 -0
  202. package/dist/x402-opener/abi.js +880 -0
  203. package/dist/x402-opener/abi.js.map +1 -0
  204. package/dist/x402-opener/facilitator-entry.d.ts +3 -0
  205. package/dist/x402-opener/facilitator-entry.d.ts.map +1 -0
  206. package/dist/x402-opener/facilitator-entry.js +37 -0
  207. package/dist/x402-opener/facilitator-entry.js.map +1 -0
  208. package/dist/x402-opener/facilitator-server.d.ts +180 -0
  209. package/dist/x402-opener/facilitator-server.d.ts.map +1 -0
  210. package/dist/x402-opener/facilitator-server.js +696 -0
  211. package/dist/x402-opener/facilitator-server.js.map +1 -0
  212. package/dist/x402-opener/index.d.ts +14 -0
  213. package/dist/x402-opener/index.d.ts.map +1 -0
  214. package/dist/x402-opener/index.js +14 -0
  215. package/dist/x402-opener/index.js.map +1 -0
  216. package/dist/x402-opener/listing-resolver.d.ts +55 -0
  217. package/dist/x402-opener/listing-resolver.d.ts.map +1 -0
  218. package/dist/x402-opener/listing-resolver.js +125 -0
  219. package/dist/x402-opener/listing-resolver.js.map +1 -0
  220. package/dist/x402-opener/refund-relay.d.ts +240 -0
  221. package/dist/x402-opener/refund-relay.d.ts.map +1 -0
  222. package/dist/x402-opener/refund-relay.js +1240 -0
  223. package/dist/x402-opener/refund-relay.js.map +1 -0
  224. package/dist/x402-opener/relayer-queue.d.ts +14 -0
  225. package/dist/x402-opener/relayer-queue.d.ts.map +1 -0
  226. package/dist/x402-opener/relayer-queue.js +18 -0
  227. package/dist/x402-opener/relayer-queue.js.map +1 -0
  228. package/dist/x402-opener/scheme.d.ts +217 -0
  229. package/dist/x402-opener/scheme.d.ts.map +1 -0
  230. package/dist/x402-opener/scheme.js +749 -0
  231. package/dist/x402-opener/scheme.js.map +1 -0
  232. package/dist/x402-opener/terms.d.ts +105 -0
  233. package/dist/x402-opener/terms.d.ts.map +1 -0
  234. package/dist/x402-opener/terms.js +212 -0
  235. package/dist/x402-opener/terms.js.map +1 -0
  236. package/dist/zktls/reclaim.d.ts +2 -2
  237. package/dist/zktls/t2-delivery-proof.d.ts +6 -6
  238. package/docs/agent-layer.md +3 -2
  239. package/docs/autonomous-privy-wallet.md +188 -0
  240. package/docs/cli.md +184 -31
  241. package/docs/langchain.md +5 -0
  242. package/docs/mcp-reference.md +75 -5
  243. package/docs/probe-capability.md +191 -0
  244. package/docs/quickstart.md +36 -1
  245. package/docs/threat-model.md +20 -0
  246. package/docs/x402.md +628 -595
  247. package/package.json +19 -17
  248. package/src/capability/probe-capability.ts +355 -0
  249. package/src/cli/args.ts +29 -0
  250. package/src/cli/commands/claim.ts +1 -1
  251. package/src/cli/commands/close.ts +36 -3
  252. package/src/cli/commands/invoke.ts +5 -2
  253. package/src/cli/commands/mcp.ts +18 -2
  254. package/src/cli/commands/open.ts +75 -4
  255. package/src/cli/commands/pay.ts +442 -0
  256. package/src/cli/commands/reclaim-unverified.ts +8 -2
  257. package/src/cli/commands/reclaim.ts +252 -14
  258. package/src/cli/commands/refund.ts +277 -0
  259. package/src/cli/commands/status.ts +17 -1
  260. package/src/cli/commands/streams.ts +10 -14
  261. package/src/cli/commands/watch.ts +7 -1
  262. package/src/cli/config.ts +139 -52
  263. package/src/cli/deps.ts +74 -1
  264. package/src/cli/errors.ts +24 -1
  265. package/src/cli/escape-hatch.ts +19 -5
  266. package/src/cli/listings.ts +43 -10
  267. package/src/cli/preflight.ts +36 -21
  268. package/src/cli/privy.ts +4 -2
  269. package/src/cli/reclaimability.ts +154 -0
  270. package/src/cli/run.ts +54 -11
  271. package/src/cli/scan-range.ts +2 -2
  272. package/src/cli/status.ts +14 -1
  273. package/src/cli/wallet.ts +2 -2
  274. package/src/discovery/rate-band.ts +172 -0
  275. package/src/escrow-generation.ts +135 -0
  276. package/src/frameworks/agentkit.ts +45 -11
  277. package/src/frameworks/eliza.ts +27 -5
  278. package/src/frameworks/langchain.ts +14 -0
  279. package/src/gateway/caller-auth-gateway.ts +320 -68
  280. package/src/gateway/http-server.ts +629 -220
  281. package/src/gateway/probe-auth.ts +191 -0
  282. package/src/gateway/signed-rate-bounds.ts +164 -0
  283. package/src/gateway/x402-opener-mode.ts +974 -0
  284. package/src/index.ts +82 -19
  285. package/src/mcp/server.ts +319 -42
  286. package/src/mcp/x402-tools.ts +621 -0
  287. package/src/network.ts +302 -0
  288. package/src/sdk/invoke.ts +6 -5
  289. package/src/wallet/autonomous-wallet-broker.ts +46 -20
  290. package/src/wallet/autonomous-wallet-protocol.ts +11 -2
  291. package/src/wallet/autonomous-wallet.ts +4 -2
  292. package/src/wallet/broker-escrows.ts +66 -0
  293. package/src/wallet/lifecycle.ts +53 -18
  294. package/src/wallet/privy-broker-server.ts +35 -25
  295. package/src/wallet/privy-session-broker.ts +58 -25
  296. package/src/wallet/privy-session-provider.ts +7 -3
  297. package/src/wallet/provider.ts +20 -15
  298. package/src/x402/facilitator.ts +3 -43
  299. package/src/x402-buyer/guarded-fetch.ts +213 -0
  300. package/src/x402-buyer/index.ts +9 -0
  301. package/src/x402-buyer/pay.ts +517 -0
  302. package/src/x402-opener/abi.ts +881 -0
  303. package/src/x402-opener/facilitator-entry.ts +45 -0
  304. package/src/x402-opener/facilitator-server.ts +1014 -0
  305. package/src/x402-opener/index.ts +13 -0
  306. package/src/x402-opener/listing-resolver.ts +202 -0
  307. package/src/x402-opener/refund-relay.ts +1743 -0
  308. package/src/x402-opener/relayer-queue.ts +18 -0
  309. package/src/x402-opener/scheme.ts +1133 -0
  310. package/src/x402-opener/terms.ts +300 -0
  311. package/dist/gateway/x402-mode.d.ts +0 -123
  312. package/dist/gateway/x402-mode.d.ts.map +0 -1
  313. package/dist/gateway/x402-mode.js +0 -212
  314. package/dist/gateway/x402-mode.js.map +0 -1
  315. package/dist/x402/delivery-oracle.d.ts +0 -108
  316. package/dist/x402/delivery-oracle.d.ts.map +0 -1
  317. package/dist/x402/delivery-oracle.js +0 -174
  318. package/dist/x402/delivery-oracle.js.map +0 -1
  319. package/dist/x402/facilitator-server-entry.d.ts +0 -3
  320. package/dist/x402/facilitator-server-entry.d.ts.map +0 -1
  321. package/dist/x402/facilitator-server-entry.js +0 -27
  322. package/dist/x402/facilitator-server-entry.js.map +0 -1
  323. package/dist/x402/facilitator-server.d.ts +0 -73
  324. package/dist/x402/facilitator-server.d.ts.map +0 -1
  325. package/dist/x402/facilitator-server.js +0 -305
  326. package/dist/x402/facilitator-server.js.map +0 -1
  327. package/dist/x402/payment-requirements.d.ts +0 -106
  328. package/dist/x402/payment-requirements.d.ts.map +0 -1
  329. package/dist/x402/payment-requirements.js +0 -138
  330. package/dist/x402/payment-requirements.js.map +0 -1
  331. package/dist/x402/relayer.d.ts +0 -41
  332. package/dist/x402/relayer.d.ts.map +0 -1
  333. package/dist/x402/relayer.js +0 -64
  334. package/dist/x402/relayer.js.map +0 -1
  335. package/dist/x402/resource-index.d.ts +0 -75
  336. package/dist/x402/resource-index.d.ts.map +0 -1
  337. package/dist/x402/resource-index.js +0 -126
  338. package/dist/x402/resource-index.js.map +0 -1
  339. package/dist/x402/verified-delivery-facilitator.d.ts +0 -285
  340. package/dist/x402/verified-delivery-facilitator.d.ts.map +0 -1
  341. package/dist/x402/verified-delivery-facilitator.js +0 -423
  342. package/dist/x402/verified-delivery-facilitator.js.map +0 -1
  343. package/src/gateway/x402-mode.ts +0 -350
  344. package/src/x402/delivery-oracle.ts +0 -285
  345. package/src/x402/facilitator-server-entry.ts +0 -35
  346. package/src/x402/facilitator-server.ts +0 -445
  347. package/src/x402/payment-requirements.ts +0 -231
  348. package/src/x402/relayer.ts +0 -122
  349. package/src/x402/resource-index.ts +0 -228
  350. package/src/x402/verified-delivery-facilitator.ts +0 -744
@@ -0,0 +1,191 @@
1
+ # `ProbeCapability` — letting the verifier check a gated paid route
2
+
3
+ > **What this changes for you as a seller:** if your listing is `gated`, the
4
+ > Metrik oracle currently cannot call your paid route at all. It can only reach
5
+ > your health route. Adopting `ProbeCapability` is what turns "the health
6
+ > endpoint answered" into "the paid route delivered". It is **opt-in**, and a
7
+ > gateway that does not adopt it is reported by the oracle as **unverifiable**
8
+ > for the paid route — never as passing.
9
+
10
+ ## The problem
11
+
12
+ A gated listing's paid route requires an `InvocationCapability` (see
13
+ [`../src/capability/invocation-capability.ts`](../src/capability/invocation-capability.ts))
14
+ signed by **the stream's buyer**: 60s TTL, single-use nonce, bound to one method
15
+ and one path. The gateway recovers that signature and checks it against
16
+ `stream.buyer` on-chain.
17
+
18
+ The oracle is not a buyer. It holds no buyer key and has no stream. So for a
19
+ gated listing there is no credential a regional probe worker could safely
20
+ present, and the paid route goes unprobed by anybody — not remotely, and not
21
+ even by the coordinator.
22
+
23
+ That is a real gap in a claim the product makes. "The seller earns only for
24
+ intervals that verified" must not quietly mean "the health endpoint answered".
25
+
26
+ ## The mechanism
27
+
28
+ A second EIP-712 type, `ProbeCapability`, signed by an **oracle signer**:
29
+
30
+ ```
31
+ ProbeCapability {
32
+ bytes32 serviceRef; // the service being probed
33
+ address oracle; // the minting signer; must equal the recovered signer
34
+ string method; // exactly one HTTP method
35
+ bytes32 pathHash; // keccak256 of exactly one request path
36
+ bytes32 nonce; // single-use
37
+ uint64 expiry; // ~30s
38
+ }
39
+ ```
40
+
41
+ EIP-712 domain: `name = "Metrik Probe Capability"`, `version = "1"`, the
42
+ gateway's `chainId`, and `verifyingContract` = the `StreamEscrowV2` the gateway
43
+ already checks streams against. The domain name is deliberately **different**
44
+ from `"Metrik Invocation Capability"`, so a buyer's invocation signature can
45
+ never be replayed as a free probe and vice versa.
46
+
47
+ Transport: base64url in the `x-metrik-probe-capability` request header.
48
+
49
+ ### Authority is public, not a shared secret
50
+
51
+ The gateway authorizes the probe iff the recovered signer is in
52
+ `StreamEscrowV2.getOracleSigners()` — a **public `view`** on the escrow. On the
53
+ live Base Sepolia deployment (`0x0f09f36Ccc05A7c9882F438721C08De314dFd46C`) that
54
+ returns three addresses today.
55
+
56
+ This is the whole reason the design beats "give the workers a credential":
57
+
58
+ - **Nothing to distribute.** No API key, no registration, no onboarding call.
59
+ A third-party seller performs the identical on-chain read and reaches the
60
+ identical verdict, with no trust in the oracle's say-so.
61
+ - **Nothing to leak.** The only secret is the oracle coordinator's signing key,
62
+ which never leaves it.
63
+ - **Revocation is already solved.** Remove a signer on the escrow and it stops
64
+ being able to probe within one signer-cache TTL (60s by default).
65
+
66
+ ### No signing key leaves the coordinator
67
+
68
+ The oracle coordinator mints **one fresh capability per probe, per vantage** and
69
+ hands the encoded header to the worker alongside the nonce. Workers hold a
70
+ bearer token for the coordinator and nothing else. Compromising every regional
71
+ worker yields no ability to mint a capability, and no ability to probe anything
72
+ the coordinator did not already ask for — the capability is bound to one
73
+ service, one method, one path, one nonce and ~30 seconds.
74
+
75
+ One capability **per vantage**, not one per probe, because the nonce is
76
+ single-use: two vantages sharing a capability would see the second rejected as a
77
+ replay.
78
+
79
+ ### A probe never consumes a buyer's budget
80
+
81
+ Three independent reasons, all structural rather than conventional:
82
+
83
+ 1. A `ProbeCapability` carries **no `streamId` and no `buyer`**. There is no
84
+ stream identified for it to be billed against.
85
+ 2. Accrual is only ever produced by an **oracle checkpoint keyed to a stream**.
86
+ A gateway call produces none, ever — the gateway is an authorizer and proxy,
87
+ not a meter.
88
+ 3. In the reference gateway the probe branch is evaluated **first and returns
89
+ unconditionally**, so it can never fall through into the stream branch. An
90
+ authorized probe decision carries only the probe — no `stream`, no
91
+ capability, nothing billable. A test asserts the stream reader is never even
92
+ called.
93
+
94
+ The gateway additionally sets `x-metrik-probe: 1` on the **upstream** request so
95
+ your own metering and analytics can exclude verification traffic. It is
96
+ gateway-asserted: any inbound copy from a client is stripped first, so a paying
97
+ caller cannot mark its own billable request as a probe.
98
+
99
+ ### Rate limiting: why 60/minute
100
+
101
+ Without a bound, an oracle-signed capability is a licence to consume your
102
+ service indefinitely for free.
103
+
104
+ The oracle checkpoints every ~15–22 seconds, so **one** vantage probes a given
105
+ service at most ~4 times a minute. T1 multi-vantage fans that out across at most
106
+ 9 vantages (the coordinator plus the oracle's 8-worker cap), giving a worst-case
107
+ honest load of **~36 probes/minute**. The default budget is **60 per minute**:
108
+ comfortable headroom for a re-execution sample and clock jitter, while capping
109
+ the free-service surface at one request per second — far below anything
110
+ economically interesting as a way to get the service for nothing.
111
+
112
+ Tune it with `METRIK_GATEWAY_PROBE_MAX_PER_MINUTE`. A useful side effect: since
113
+ every capability is single-use and ~30s-lived, the rate limit is also what
114
+ bounds the replay cache — at most `maxPerMinute × ttl/60` probe nonces live at
115
+ once.
116
+
117
+ ### Replay protection reuses the existing cache
118
+
119
+ The probe path calls the **same** `NonceReplayCache` the buyer path uses, so a
120
+ nonce can never be spent once as a probe and once as an invocation. The nonce is
121
+ consumed _before_ the rate-limit check, so a captured capability replayed at
122
+ volume is rejected as a replay rather than eating the honest probe budget, and
123
+ _before_ the on-chain signer read, so a flood cannot amplify into RPC load.
124
+
125
+ ## Enabling it
126
+
127
+ ```bash
128
+ METRIK_GATEWAY_PROBE_CAPABILITY=true # off by default
129
+ METRIK_GATEWAY_PROBE_MAX_PER_MINUTE=60 # optional
130
+ METRIK_GATEWAY_PROBE_SIGNER_CACHE_SECONDS=60 # optional
131
+ ```
132
+
133
+ There is **no credential to configure**. The signer set is read from the
134
+ `METRIK_GATEWAY_RPC_URL` and escrow the gateway already uses.
135
+
136
+ Not using the reference gateway? Implement the verification in this exact order
137
+ — cheapest and most local first, so an unsigned or replayed flood cannot amplify
138
+ into RPC load:
139
+
140
+ 1. Decode the `x-metrik-probe-capability` header; malformed → `403`.
141
+ 2. `now >= expiry` → `403`.
142
+ 3. Recover the EIP-712 signer; it must equal `capability.oracle` → else `403`.
143
+ 4. `capability.method` must equal the request method → else `403`.
144
+ 5. `keccak256(path)` must equal `capability.pathHash` (path only — no query, no
145
+ fragment, no trailing slash except root) → else `403`.
146
+ 6. `capability.serviceRef` must be one you front → else `403`.
147
+ 7. Consume `capability.nonce` single-use → replay is `403`.
148
+ 8. Rate-limit → `429`.
149
+ 9. `capability.oracle` must be in `getOracleSigners()` → else `403`. If you
150
+ cannot read the set, **deny** (`403`); do not serve on a stale set.
151
+
152
+ Then proxy upstream and **do not meter, bill or settle the call**.
153
+
154
+ ## Failure modes, and what each one means to the oracle
155
+
156
+ Every denial is a distinct machine-readable `reason` in the JSON body:
157
+
158
+ | Reason | Status | What it means |
159
+ | ----------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------- |
160
+ | `probe-not-enabled` | 403 | This gateway has not adopted `ProbeCapability`. The oracle reports the paid route **unverifiable**. |
161
+ | `malformed-probe-capability` | 403 | Header was not a decodable signed capability. |
162
+ | `probe-capability-expired` | 403 | Past `expiry`. |
163
+ | `probe-invalid-signature` | 403 | Signature does not recover to the claimed `oracle`. |
164
+ | `probe-method-mismatch` / `probe-path-mismatch` | 403 | Capability was not minted for this route. |
165
+ | `probe-service-ref-mismatch` | 403 | Minted for another service. |
166
+ | `probe-nonce-replayed` | 403 | Nonce already spent. |
167
+ | `probe-rate-limited` | 429 | Free-probe budget for this window is spent. |
168
+ | `probe-signer-not-authorized` | 403 | Signer is not in `getOracleSigners()`. |
169
+ | `probe-signer-set-unavailable` | 403 | The set could not be read fresh enough. Fail closed. |
170
+ | `ambiguous-probe-mode` | 400 | Request carried a probe capability _and_ a buyer capability or `X-PAYMENT`. Refused rather than guessed. |
171
+
172
+ ## Honest limitations
173
+
174
+ - **This is an adoption ask.** We ship the reference implementation because we
175
+ run the reference gateway, but a third-party seller has to adopt it. Until
176
+ they do, their gated paid route stays health-route-only and the oracle says so
177
+ out loud rather than implying coverage it does not have.
178
+ - **A gated seller can stay unverifiable on purpose.** A hostile gateway can
179
+ simply answer `403` to every probe and remain in the "unverifiable" bucket.
180
+ That gains it nothing it does not already have today — under the oracle's
181
+ `strict` enforcement an unverifiable paid route accrues nothing, and under
182
+ `eligible` it is exactly today's health-route-only behaviour, counted and
183
+ surfaced. What it can never do is be counted as _passing_.
184
+ - **Delivery, not correctness.** A passing probe is evidence the paid route
185
+ produced a fresh, spec-conforming response for _this_ challenge. It is not a
186
+ proof the output is correct. See
187
+ [`../../streamproof-protocol/docs/verification-model.md`](https://github.com/Absol-Labs/metrik-protocol/blob/main/docs/verification-model.md).
188
+ - **The signer set is federated today.** All three addresses in
189
+ `getOracleSigners()` are keys held by one process, and one of them operates
190
+ the live listings. `ProbeCapability` inherits that posture exactly — it makes
191
+ the _paid route_ checkable, not the verifier independent.
@@ -293,6 +293,40 @@ const { reclaimResult } = await agent.reclaimStream({
293
293
  escape-window rules, and `claimed + fees + reclaimed == deposit` conserves the escrowed
294
294
  funds exactly.
295
295
 
296
+ ### 7b. Or pay a seller over x402 (no gas needed)
297
+
298
+ A Metrik x402 seller (an HTTP `402` with an x402 v2 `exact` quote) can be paid in one
299
+ call. The payment opens the same kind of stream — `deposit = price`, earned per verified
300
+ second — and the same spend mandate bounds it before anything is signed:
301
+
302
+ ```ts
303
+ import { defaultNetwork } from "@absol-labs/agent";
304
+ import { payX402WithMandate } from "@absol-labs/agent/x402-buyer";
305
+
306
+ const paid = await payX402WithMandate({
307
+ url: "https://x402.137.23.50.249.sslip.io/transform",
308
+ init: {
309
+ method: "POST",
310
+ headers: { "content-type": "application/json" },
311
+ body: '{"text":"# hi"}',
312
+ },
313
+ signer: account, // USDC only, no ETH
314
+ network: defaultNetwork(),
315
+ signedMandate,
316
+ spentSoFarUsdc: 0n,
317
+ nowSeconds: Math.floor(Date.now() / 1000),
318
+ });
319
+ console.log(paid.metrikStreamOpener); // streamId, opener, refundUrl, deposit, rate
320
+ ```
321
+
322
+ Getting the unearned part back is not automatic: close, then reclaim, through the seller's
323
+ gasless relay (the `metrik refund` command below, or the SDK's `refundClient`).
324
+
325
+ Full details, including the mandate mapping: [the buyer section](./x402.md).
326
+
327
+ From a terminal: `metrik pay <url> --json '{"text":"# hi"}' --max-amount 0.1`, then
328
+ `metrik refund <streamId> --refund-url <url> --close --reclaim`.
329
+
296
330
  ---
297
331
 
298
332
  ## 8. Five ways to integrate
@@ -394,4 +428,5 @@ Metrik proves **verified delivery** (responded, correctly-shaped, within SLA to
394
428
  traffic) — **not output correctness** (that the model's answer is right). Pitch and treat
395
429
  it accordingly. The full journey, run live against the real deployed escrow on Base
396
430
  Sepolia, is [`scripts/e2e-cdp.ts`](../scripts/e2e-cdp.ts) (`pnpm build:e2e && pnpm
397
- e2e:cdp`) — the working reference for everything above.
431
+ e2e:cdp`) — the working reference for everything above; its x402 leg is
432
+ [`scripts/e2e-x402.ts`](../scripts/e2e-x402.ts) (`pnpm e2e:x402`).
@@ -22,6 +22,9 @@ In scope:
22
22
  - the mandate-gated SDK wrapper in [`src/sdk/client.ts`](../src/sdk/client.ts)
23
23
  - Metrik `402` verified-stream opens in [`src/x402/facilitator.ts`](../src/x402/facilitator.ts)
24
24
  (a Metrik-native challenge flow, not the x402 protocol — see [docs/x402.md](./x402.md))
25
+ - the x402 v2 opener facilitator in [`src/x402-opener/`](../src/x402-opener/) and the
26
+ gateway's x402 v2 mode in [`src/gateway/x402-opener-mode.ts`](../src/gateway/x402-opener-mode.ts)
27
+ (both off by default — see [docs/x402.md](./x402.md))
25
28
  - MCP fund-moving tools in [`src/mcp/server.ts`](../src/mcp/server.ts)
26
29
  - zkTLS consumer delivery proofs in [`src/zktls/reclaim.ts`](../src/zktls/reclaim.ts)
27
30
  - wallet custody in [`src/wallet/provider.ts`](../src/wallet/provider.ts)
@@ -43,6 +46,23 @@ Out of scope:
43
46
  | Mandate replay | A previously valid signed mandate is replayed after revocation or outside the intended lifetime. | Mandates are EIP-712 signed over `mandateId`, `owner`, `chainId`, `issuedAt`, expiry, and policy hashes. `checkMandate()` verifies signature, revocation, expiry, then policy. Integrators can revoke by `mandateId` and track cumulative spend. | [`src/mandates/mandate.ts`](../src/mandates/mandate.ts), [`test/mandate.test.ts`](../test/mandate.test.ts), [`test/mcp.test.ts`](../test/mcp.test.ts) | Replay protection is only as strong as revocation and cumulative-spend state freshness. The signed payload itself is bound to one chain and one owner, but revocation is local state today. |
44
47
  | False or weak delivery evidence | A consumer submits a proof that is validly signed by the zkTLS system but not bound to the intended request or stream context. | The Reclaim adapter re-verifies every proof locally against the exact URL/method/body/match/redaction spec supplied by the caller, and binds the proof context to buyer/stream metadata before returning it. MCP only exposes the public-request subset so secrets do not leak through tool arguments. | [`src/zktls/reclaim.ts`](../src/zktls/reclaim.ts), [`src/x402/facilitator.ts`](../src/x402/facilitator.ts), [`src/mcp/server.ts`](../src/mcp/server.ts), [`test/reclaim.test.ts`](../test/reclaim.test.ts), [`test/x402.test.ts`](../test/x402.test.ts), [`test/mcp.test.ts`](../test/mcp.test.ts) | L2 is still consumer-supplied evidence. A malicious consumer can withhold proofs, and settlement must still treat L1/oracle evidence as authoritative on failure, ambiguity, and expiry. |
45
48
 
49
+ ## x402 v2 opener threats
50
+
51
+ The opener path moves a buyer's USDC only under that buyer's own EIP-3009
52
+ signature, so no agent-held key spends and no spend mandate applies; the
53
+ threats are about where the signed payment can end up.
54
+
55
+ | Threat | Mitigation | Code / tests |
56
+ | ------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
57
+ | A stock x402 facilitator (or anyone holding the signed payload) submits `transferWithAuthorization` to the opener directly, stranding the payment | Only `MetrikOpenerExactScheme` settles, via `deployAndSettle`; its stock verifier gets a signer that cannot broadcast. The gateway refuses to start, and fails closed (503) later, unless the facilitator's `/supported` marker names its exact factory/escrow/token/chain. `PAYMENT-SIGNATURE` is never forwarded upstream. No discovery extension is ever declared. | `src/x402-opener/scheme.ts`, `src/gateway/x402-opener-mode.ts`; `test/x402-opener-gateway.test.ts`, `test/x402-opener.fork.int.test.ts` |
58
+ | A forged or tampered `payTo`, terms or listing redirects funds | `payTo` must equal `factory.predict(terms)` read on-chain (never code/codehash); `(operator, serviceRef)` must resolve to exactly one operator-signed listing via discovery signature verification; amount bounded by `rate × maxDuration` | `test/x402-opener-scheme.test.ts`, `test/x402-opener-config.test.ts` |
59
+ | Success reported without a stream | `settle` returns `success: true` only from a mined receipt carrying the escrow `StreamOpened` (buyer = opener) and the opener `StreamOpenedFor` for this payer/nonce/amount | `test/x402-opener-scheme.test.ts` |
60
+ | One payment buys several served responses (a replayed `PAYMENT-SIGNATURE`) | At most one successful settle per authorization (chain + asset + payer + nonce) per facilitator instance; the gateway refuses an in-flight or settled authorization with `409` before the upstream runs. In-memory, per instance: run one instance | `test/x402-opener-scheme.test.ts`, `test/x402-opener-gateway.test.ts`, `test/x402-opener-regressions.fork.int.test.ts` |
61
+ | Concurrent payers fail on the relayer nonce after being served | Relayer submissions are serialized | same |
62
+ | Dust payments drain relayer gas; unauthenticated `/verify` amplifies RPC load | Minimum amount (default 0.01 USDC, advertised; the gateway refuses a lower price), `/settle` rate limit per token, `/verify` requires the token by default | `test/x402-opener-config.test.ts`, fork regressions |
63
+ | A failed upstream still charges the buyer | The gateway settles only when the upstream status is `< 400`, and a failed settle sends no body | `test/x402-opener-gateway.test.ts`, fork E2E |
64
+ | Relayer key or facilitator token leaks | Env only, never logged or echoed in errors; `/settle` requires the bearer token (constant-time compared) | `src/x402-opener/facilitator-server.ts`; `test/x402-opener-config.test.ts` |
65
+
46
66
  ## Fund-Moving Paths
47
67
 
48
68
  These are the autonomous fund-moving paths in the current agent layer: