{"_id":"@agent-cards/commerce-sdk","_rev":"19-505cd4084172087bcbd9b83f20139961","name":"@agent-cards/commerce-sdk","dist-tags":{"latest":"0.18.6"},"versions":{"0.0.0-stage":{"name":"@agent-cards/commerce-sdk","version":"0.0.0-stage","_id":"@agent-cards/commerce-sdk@0.0.0-stage","stub":true,"maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"1cbfa1b53e3f3068a79b4e0afd143f5d0ac03191","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.0.0-stage.tgz","fileCount":2,"integrity":"sha512-1t6tnjDOBtqfP3b735UwWddGI+2nKHyhn0ygfsY0fhNiIxUgwNfSySKyuQ8zh0VAA/A7C3rxVplFY1gHFKHjqQ==","signatures":[{"sig":"MEYCIQDrCFIfGsXtFQebWoGN9bMpl8e+dTGY7jl/BDKe/yiHoQIhAOZfsT2zGb4SsOU25ZfN6M+PsWxyZjk/7tZ+ilCqELny","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":347},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"description":"Temporary package placeholder for staged publishing","directories":{}},"0.1.0":{"name":"@agent-cards/commerce-sdk","version":"0.1.0","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.1.0","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"e48fa9f02d34eac6bb6395691e581d28adfe1306","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.1.0.tgz","fileCount":24,"integrity":"sha512-EWQGg033KMbHPDT7M77pklZ15jCYrYfXR9khncGVNSt4/K/uJ2Y8sZhJlnKQ6MgiI+tjeqF7VDDgF0jg4F30+Q==","signatures":[{"sig":"MEUCIGl52/UIWefn11gMig14JC8jtZW2HoARW7f1c3OpuWsCAiEAiQPM/nRxyu40pX2bcm031EeK4XM2br3hNeHyuRn0eqU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIAkU1lcvmewMLsfyWVYIPxe6KKuikJD/HlIlfOx4vATQAiEA7DQWIU99Mwczl6DmNrZ6iZD7UNvgRmJ8z9S0gZeIhGc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":150046},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"d199b73c8fd5298bc32dc8e69094f6c31bd4fb4a","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.8","description":"Give your agent one tool that buys for your shoppers at real stores, and hear what happened to each purchase from a signed webhook.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.1.0_1792118463664_0.9171506655504471","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@agent-cards/commerce-sdk","version":"0.2.0","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.2.0","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"b5a12175cf96737b3dcbbf44a682da08743ae2c0","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.2.0.tgz","fileCount":26,"integrity":"sha512-ZtbO8+LVFK6ae5MGw8bb1siyXN2fy5EX4vhw2XWo9Qy99jSo73F5pvDWpLki7tn9Dvray/lS1yVfkNh4xH4AWw==","signatures":[{"sig":"MEUCIF0n3miqJQ4vjXTmBZenj1gtI9V3d3ZDlKN7t406gCgNAiEA/3WhKGlKOhBQ2Y8IILZhHmbeAG5SubZrdLlfAnY36IA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIF3my/rxtsWQE6EaNOl/ohJDNyC32KGrxMdhDlNOxw3eAiEA5TJ0iaajzZcHN2lspEu4g+4YEgyJK57vDyvOqC60bD0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":169011},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"509db8347ce1bd9a5934c1e3efbfcdf2304a361d","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.8","description":"Give your agent one tool that buys for your shoppers at real stores, and hear what happened to each purchase from a signed webhook.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.2.0_1792351727871_0.8880486104079903","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@agent-cards/commerce-sdk","version":"0.5.0","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.5.0","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"b9adeb1338b415e8cc1e683d7c65342a8b29940f","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.5.0.tgz","fileCount":30,"integrity":"sha512-bEu98dfJTt5GsxMCP6mrrEoedV/HhFq8052pXT2CUHjC7lShmrjlS92Omf9xGCuxdXSg4ramSvZUaC9XsZvL7g==","signatures":[{"sig":"MEQCIEB1O9AAzmOLnWSbAZJBa0UdRc1C7M2R8Q6/mx4UaDdHAiAPK9y5f2Z/QINWXfWZbFZEezKQygGsn/DyaTbyKCxp1g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIAmtipzwArGd9Fwd61ZpCfQMdxKBc+X9xzjjfq50eNIpAiB+JM7x2aiSy0ma0VUe9ILu2A5wYEHN90bDETvhqIFpIw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":219746},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"14cebf690545af5fa7754396c0e045104329a7dd","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.8","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.5.0_1792442552297_0.14333446820505946","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"@agent-cards/commerce-sdk","version":"0.8.0","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.8.0","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"17408e4ba827ffd6e64178b79621bc753dcbf976","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.8.0.tgz","fileCount":34,"integrity":"sha512-lkcR9IQA+l45laQHSyYNbG6AhR0Ry39G2HBeu31uAlXcnheD+Q0OlxLwl+I3A/te+6TsQIG06k2we16T79TKnQ==","signatures":[{"sig":"MEQCIFiwdRqiAKVOE0D4NRp6D6A2+Tamb53VhuYPEGpDC0XNAiBOSrSgAjrXflTRm0BsAPu9EvJ3er7SkA97YfBbzJ9BZQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQD4KKRgHH2aJZZkynAIVZxE6ybvgaNiffh6IskF+ER0sgIhAMSal9LddP1/1dgCMfH8l2SVa+31kLwUUSLtN56CNpnJ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":284926},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"8de79e8b62efa54077035241fe533672ddf1a20f","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.8","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.8.0_1792508578838_0.7935805535018248","host":"s3://npm-registry-packages-npm-production"}},"0.9.0":{"name":"@agent-cards/commerce-sdk","version":"0.9.0","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.9.0","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"0804387007a53ffda0d84929c6798a01c23b450c","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.9.0.tgz","fileCount":34,"integrity":"sha512-hW1W9AmpCH62NiH5A/SBZ8b/ijR+Ij7aqJGl4cN8yujTqvljQ2FttzOU6CbRBI6Jx+zUR06i8QpBW/iY2lGh4A==","signatures":[{"sig":"MEQCIA7QSYzrd111Nl83SGRvPtvVVuiZs117/AcXhLlsISEWAiBY2UKt8Itc4Mlo8pJc60pBSRnSNfyY1m6x67y2jf+frA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIHKF1sBQccA1Fz4j+2iuPWqPXxvac1uS6cMt1anQC/yJAiBNvg+YYSKftN0LvE2fx1ZOCtmlNz6p8IrDElCFG5Vwvw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":312924},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"dd1e4b16b33a9f3b124fc57fa597f5e87961b005","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.8","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.9.0_1792520107992_0.12447317159742832","host":"s3://npm-registry-packages-npm-production"}},"0.10.0":{"name":"@agent-cards/commerce-sdk","version":"0.10.0","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.10.0","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"85a220b05045430481202684c8b4c52e2b314cc8","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.10.0.tgz","fileCount":34,"integrity":"sha512-6Ek+hNT5i0m0Z1+xEYX4G6LfyaePF/GUskVKNQXsjKgTOsKj9mCqfHMJDbCwOJmpwFW5yjHZJSGH3c/M0YROJA==","signatures":[{"sig":"MEUCIQDoUmATGFYH8lFeieJ5nvsYhAtVpUKCcDKiky/xWb1axgIgAyLXU347MgLRBwDg87OQwRo1gu6dQeow75MlPhGHuaw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCkSpDx5u4/Ohz8cmHDlNlN4rdaHNU4YGNmKBDzpMfQFQIgWiJvcqqsMTWitYfhStg+EY0VIe/vY+WGc0vnqJOsVN8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":381971},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"4df5303863f2df04139f458d04fbdbb491462b73","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.8","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.10.0_1792535124672_0.3600633680019316","host":"s3://npm-registry-packages-npm-production"}},"0.11.0":{"name":"@agent-cards/commerce-sdk","version":"0.11.0","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.11.0","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"73219b80592c4df2338878d4ea054fe6ca7f2d26","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.11.0.tgz","fileCount":34,"integrity":"sha512-OaY4oTlxKjGBxqKXtT1G52/V6dlA7kzjp4GCXb3wwchFUhxSEHGONc8nbwQGTy87PM2v4veU4FNHXC/puwOHZQ==","signatures":[{"sig":"MEYCIQCH42fjHjox6pJAWqRBsWSiDL6F3KAj47HMM+Lr2phqowIhAPKjigNt3VrDbP/qwJTv6YGiI+QzoCGKOwoMJaNsjFvC","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDEHCdmXQX29Oj9YlrUge4UbPNES9UK6zM0tkr/bS+0KQIhAPngH4xEUF9WuoXXEjmV9XzDIE9dW2NzhH1hgky0LxBU","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":396465},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"c81588a4a3077ddf8a20d55e93b8fb6965bdd221","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.8","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.11.0_1792550078155_0.9566062049486095","host":"s3://npm-registry-packages-npm-production"}},"0.13.0":{"name":"@agent-cards/commerce-sdk","version":"0.13.0","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.13.0","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"c1cf70f51ade34125a4f130b92cbeec0f3af7c04","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.13.0.tgz","fileCount":38,"integrity":"sha512-8vqFxmRoBXCovdUGpqei5rIzmfvdHReWMDZXYk5UWd7N5E+qbLn5LguIrAKCdoEdC3owkfI4SQ74GXonJfexyQ==","signatures":[{"sig":"MEQCIBw5Q3MRBC2K42htNhmgnNVJNGAjIvO0KZHuQphfIkV4AiAfD86kXZKJlHamm2tXGR3EXjhH03A5hu7mKAjRLYJn6w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQD/rmHMHev333AGLwBQ+esga5rNCEtl+EyHNhPFxtTRTwIgCpKs8/liHXERcRw/1AyD3b4mjYIpZlisk5BgRJyh2es=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":487698},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./browser":{"types":"./dist/browser.d.ts","default":"./dist/browser.js"}},"gitHead":"3b3458825eb597c0a19b27bd44f9b30d6d2f98f9","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.9","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.13.0_1792858781557_0.08141873653604881","host":"s3://npm-registry-packages-npm-production"}},"0.14.0":{"name":"@agent-cards/commerce-sdk","version":"0.14.0","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.14.0","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"983fbff12ec8a3fa04d101e623bc5f9078ebc251","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.14.0.tgz","fileCount":40,"integrity":"sha512-1In1JW97VOxIJoEu3tbaI8ZK6kUsgsaiLQSWWW5CPccTCxe0xKR26A3Vmm1wACfdfT/IJaWuVqmR1+dy6puVMg==","signatures":[{"sig":"MEUCIG5q4+3yOWnrln3gB4i1a+IISkj3n9E1hp8kdOD0ev15AiEAqn29Nn1Ua8Luh2o8HEDlZUMDg+3OWQh7JZuidvflHBg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIHS+oRxQtNv1kO1K6CStz/1R7q8MvJS47l/0zzZKCoplAiBW012VD8BRssxOLGDJEPRqzx9tHSbSeCtRjN0jcCgAyA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":560717},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./browser":{"types":"./dist/browser.d.ts","default":"./dist/browser.js"}},"gitHead":"7e23de723252801c5a57a86bad555a0695241a72","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.9","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@opentelemetry/api":"^1.0.0"},"peerDependenciesMeta":{"@opentelemetry/api":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.14.0_1793107528458_0.9297339205226509","host":"s3://npm-registry-packages-npm-production"}},"0.15.0":{"name":"@agent-cards/commerce-sdk","version":"0.15.0","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.15.0","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"bb25bd3748cfcff519749b1386989ea8d1a32356","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.15.0.tgz","fileCount":40,"integrity":"sha512-0RggUGekUbTYKAH0b9wr7nV9naQGwI0Ql5eh2Hzp3JwRr+GRm/KAKfm71r+mqIE0U5QDXmHTJCBo1zmvZAzadQ==","signatures":[{"sig":"MEUCIQCuG7/H/5ByvcK9uEBgSmMNqTMQuYq4C2THRLfsrcTvEgIgENBHDrKvYg38xGRiNxZkLNbve/9gabd8P4+NMS9o33Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIHFtv8qQnZ5L+gnBUrnesjlUSyk+/P5skxShvP7r3+eZAiAKq9D+wqtTsa5wD1qa269qVPiCDJju9C0TjiMJtwyGQw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":572853},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./browser":{"types":"./dist/browser.d.ts","default":"./dist/browser.js"}},"gitHead":"61cd88d1d4a6ec9d74343adfc580e585b1498ec5","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.9","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@opentelemetry/api":"^1.0.0"},"peerDependenciesMeta":{"@opentelemetry/api":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.15.0_1793118564795_0.7212862963648015","host":"s3://npm-registry-packages-npm-production"}},"0.16.0":{"name":"@agent-cards/commerce-sdk","version":"0.16.0","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.16.0","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"933fa9c623ce6bf3b4e48c43063196d6f68ee60e","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.16.0.tgz","fileCount":46,"integrity":"sha512-XrrxZ3WIVnP6UwyuyUBjJgJQ0L2hwEEbkjjXfmtNucsuZnzS+qxoV2KadxOgbj2hMXO/s44RibC4XFisW3PmXw==","signatures":[{"sig":"MEQCIHz3Xu97PHnUpj5QkpGtm+GSwBdwpqnLK2SyjS0WVUEMAiBtvqRnTzsqoD1RIsGguTW4VMUQXLQTETKUY/viE9Gymg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDElkgBp+ZDaenXXgLiJwwCnX6SV/eAs33qGIhse6T5KgIgOOkbeODXUdqgYXaCnbAdp//ZQsarZSBmIwR03gECF7U=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":662414},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./browser":{"types":"./dist/browser.d.ts","default":"./dist/browser.js"}},"gitHead":"93e41b8370b5bfe77d68e2b04fab696f680c2c11","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.9","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@opentelemetry/api":"^1.0.0"},"peerDependenciesMeta":{"@opentelemetry/api":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.16.0_1793138768985_0.060633307631895006","host":"s3://npm-registry-packages-npm-production"}},"0.17.0":{"name":"@agent-cards/commerce-sdk","version":"0.17.0","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.17.0","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"2589c236be0466c073af57ea814cc835ff7c30ae","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.17.0.tgz","fileCount":46,"integrity":"sha512-EP5lFH9r+rXZ61wA+BVUXB0hw9es4rlpfvxYR4NMau9xo14YYyeJmDo5glvEkfBIl3ol8j0WkZX5NepkdBIx8g==","signatures":[{"sig":"MEYCIQCeNRAWm/sxafjV7h1daZsKv/Z1auHj14iN8Wr+l4SEnAIhAMatZkTPxXA4CaU09QEXoKUgadIVt6lHS4RiCNw7vLWJ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQD1aUOMAl+YkhsapTdjfmhcZoDS5B7V0EYpLENcv/EiJgIhAN2fB/YH/Pp588Q9ioNaEqB7TGEjwJZ7Guesvdofze+e","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":705110},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./browser":{"types":"./dist/browser.d.ts","default":"./dist/browser.js"}},"gitHead":"9287c588408e29c37124e425607711b987df3b6f","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.9","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@opentelemetry/api":"^1.0.0"},"peerDependenciesMeta":{"@opentelemetry/api":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.17.0_1793151004999_0.30159419126257137","host":"s3://npm-registry-packages-npm-production"}},"0.18.0":{"name":"@agent-cards/commerce-sdk","version":"0.18.0","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.18.0","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"d146185fc453e63fd92065f9c42e407aa8edd940","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.18.0.tgz","fileCount":46,"integrity":"sha512-5YELfRFAp9kj7UKau6L32vQx4mw2EjuUMe8Rnwy/+DbVYfBeYN8Yb3B4tRGUREHzqoSl3MPDR8cB0q3cuzsvnw==","signatures":[{"sig":"MEUCIQDrzLOt4foZ0I1P3yMQ0nYqQpaIptTT31ph6cmkj5rSQwIgSWcjNV+n0ZkGiu4JYa80ZSFjWx4JcgtYscnf4l6CkWQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIBI2Vgi74HgemBnCmRRIzulzivhzTVcHnSTXxN/JSii6AiEAzb961olYYiEX/PhJgYo8deL/8YN8V0vsoDLc1r57ESk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":711963},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./browser":{"types":"./dist/browser.d.ts","default":"./dist/browser.js"}},"gitHead":"7338bc3f41dd3d3df8a665a8bf46a5b6679d938b","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.9","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@opentelemetry/api":"^1.0.0"},"peerDependenciesMeta":{"@opentelemetry/api":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.18.0_1793153324741_0.5787759183047008","host":"s3://npm-registry-packages-npm-production"}},"0.18.2":{"name":"@agent-cards/commerce-sdk","version":"0.18.2","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.18.2","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"90ed6fd05a6d3663825cf976e29f1d510c8b4503","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.18.2.tgz","fileCount":46,"integrity":"sha512-5MDNhtGKi+yzn5KL+1PkK1khQliH12+7ryZMOEN5XzuLO42cDthUMy8f0b4fF3AlVWoyyfrzZCmRQXb+nJFppQ==","signatures":[{"sig":"MEYCIQCh3AO0IcrZwlFmEMcwPvSP+hcSm5T068SoM8a5YyiSJwIhAMby7ta/f97AH7wMB6LZfiXpGlHnexBD+gWvdDpgjshB","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCL12FJWI43LaWAee08eVA/43E1o0olWFFlhiXtloNcngIgIR61/zD1vmzQcGC82lMMf3EMC1+H0jkg2HYsVXpUpw0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":721250},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./browser":{"types":"./dist/browser.d.ts","default":"./dist/browser.js"}},"gitHead":"80c9b2e21b60b01192962cdcac689ad3eebc4c5d","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.9","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@opentelemetry/api":"^1.0.0"},"peerDependenciesMeta":{"@opentelemetry/api":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.18.2_1793180110714_0.7446737329866162","host":"s3://npm-registry-packages-npm-production"}},"0.18.3":{"name":"@agent-cards/commerce-sdk","version":"0.18.3","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.18.3","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"dist":{"shasum":"56dd46a2c9d783835fb2186998cd78540dca4d8e","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.18.3.tgz","fileCount":54,"integrity":"sha512-9CUxgGGTS3w6ivTsiA4x/W19DYrWKruu62LghvYn0hoiGoHzSqER6ZvFDSpMvEhJgeIInBFFPx49BfaXrKOVYw==","signatures":[{"sig":"MEYCIQCqdfCsuqSAnX1Wf7EdRLbAxbeYhu3XS+OImX4RX3foGwIhAJFsKfEwI4/Vp6wIMu11vEgss1F1EFJOLxoI7wXrWEv1","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCzSJjdYWJ5lrHEh4oanjfqR6Mwf9EtrzvnKTaGnB6O+gIgah9N5GfT9lqfsOT7AdX/+gCZbabKeh4dI39rstRVdcU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":753792},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./browser":{"types":"./dist/browser.d.ts","default":"./dist/browser.js"}},"gitHead":"a409071ef135d67d805925e4c629c7402df67547","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.9","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@opentelemetry/api":"^1.0.0"},"peerDependenciesMeta":{"@opentelemetry/api":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.18.3_1793283415240_0.259220682163979","host":"s3://npm-registry-packages-npm-production"}},"0.18.4":{"name":"@agent-cards/commerce-sdk","version":"0.18.4","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.18.4","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"homepage":"https://opencommerce.sh","dist":{"shasum":"d85be847a1e57076d2ad92fe1b0238fe192b4d92","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.18.4.tgz","fileCount":54,"integrity":"sha512-G71kszpURsVLwKUQnTC12PTSSE//bBD5JjJo6ctYSWxvMc5yDcDcHZ069wNN8AExPPEgJsnOAyElGwJIZFQRPg==","signatures":[{"sig":"MEYCIQDwcZm7LU1Xf6lUdHAy1ucgzKv8eQn8KmcgJkeaToy8OAIhAPGqsq7YKbNmte37Wk+nXPdKGbjOyGCxmoieP5sFNN0y","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDw1L3Pvb/Las9QNq1J0ywK81iZ88/cGrVwZ28l7+5BiAIgfLZFaxHXfEtdZVObyB4ZvUYxj+RmgdiKV5C0Ma8LmZM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":755044},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./browser":{"types":"./dist/browser.d.ts","default":"./dist/browser.js"}},"gitHead":"86d1daafe6b5c9a0bfc2efa5aa926f3a435a16b0","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.9","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@opentelemetry/api":"^1.0.0"},"peerDependenciesMeta":{"@opentelemetry/api":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.18.4_1793296070686_0.33978288198021156","host":"s3://npm-registry-packages-npm-production"}},"0.18.5":{"name":"@agent-cards/commerce-sdk","version":"0.18.5","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"license":"SEE LICENSE IN LICENSE","_id":"@agent-cards/commerce-sdk@0.18.5","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"homepage":"https://opencommerce.sh","dist":{"shasum":"1c7b0c5309de450851a67333fcf3220a1ae85903","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.18.5.tgz","fileCount":54,"integrity":"sha512-LfQ8pS3jfn9jus7pXcxUEfgBcOYEOW2FpOVS6eEeGQDazpaxKixtoX7IoAWtjUW1FXcBktPcA+oAkEM3KUzltA==","signatures":[{"sig":"MEUCIQCd1BF9BrmgtgzMZYzJ23snoj/gAQRb6QKRt1ccIIuPIQIgWQgfKco1s4GuMap+G+bRFZr55NVenac8dm2YMdKamyU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDZdmq2ThiALvk/P6Pm5GLR3yJEd4txgISvStMwJtn9eAIhAIw4haUKY8W+1O7whSyI0MuOqB60hz9uNjZI4SgvlpxS","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":768377},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./browser":{"types":"./dist/browser.d.ts","default":"./dist/browser.js"}},"gitHead":"e5e36afa5e9a944e17b549c748cf080c75bbfbc7","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build"},"_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"_npmVersion":"10.9.9","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@opentelemetry/api":"^1.0.0"},"peerDependenciesMeta":{"@opentelemetry/api":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/commerce-sdk_0.18.5_1793314540755_0.42201630215427843","host":"s3://npm-registry-packages-npm-production"}},"0.18.6":{"_id":"@agent-cards/commerce-sdk@0.18.6","dist":{"shasum":"15db2466bb709241563e9968e862b6796f0ce1ff","tarball":"https://registry.npmjs.org/@agent-cards/commerce-sdk/-/commerce-sdk-0.18.6.tgz","fileCount":62,"integrity":"sha512-TH3VRe/6xqqFO8O04Hnwc5dNoCeR11cyYZ/KW6Hk5eK+nZXuUpC3jwKqXNa6z3+1VcVr0mKOlCyn5n5ztK+11w==","signatures":[{"sig":"MEUCIQDANkw0dWddZ8qhEcKoOOPWD/QLGwtbymR3UGK4QI6M1wIgX7KK9e8yXvGKfvt5q0ICsL/HX+ivdcqvWQ5MzXz3qPk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHJyF+2wv2oN4zw4M6ZRcS/op5CMi7Ck5TBgB2YLq9kMAiAMLVXgjyXw+0ojSeoTZHk9goP1tHBoVo55Y7v2uPZ13g=="}],"unpackedSize":803774},"main":"dist/index.js","name":"@agent-cards/commerce-sdk","type":"module","types":"dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./browser":{"types":"./dist/browser.d.ts","default":"./dist/browser.js"}},"gitHead":"d62562747553e8050c94d16c5e8b7ce3ff0f4afc","license":"SEE LICENSE IN LICENSE","scripts":{"test":"pnpm build && node --test test/*.test.mjs","build":"node scripts/app-instructions.mjs && npx -y -p typescript@5.9.3 tsc","verify:pack":"node scripts/verify-pack.mjs","_comment_pack":"verify:pack lists what npm would publish (npm pack --dry-run) and fails on a missing manifest target, README or example, or on a test, source, shim or build-cache file; then it loads the built root and checks the names the README imports. The release workflow runs it after the build.","_comment_build":"Zero runtime dependencies: node:crypto is the one import, and the buy tool calls the global fetch. TypeScript is pinned, not installed, as in @agent-cards/sdk. types/node.d.ts declares the two node:crypto functions the source calls, so the build needs no @types package and the published declarations name no Node type; FetchLike names AbortSignal, which every runtime with fetch declares.","prepublishOnly":"pnpm build","_comment_instructions":"The build first copies the instructions for an app's own model (appInstructions) from apps/agent-voice/kb/app.md into src/app-instructions.generated.ts, which git ignores, so the published text always matches the voice package at the commit it was built from."},"version":"0.18.6","_npmUser":{"name":"pipeabello","email":"f@kasegu.llc"},"homepage":"https://opencommerce.sh","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"_npmVersion":"11.21.1","description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","directories":{},"maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"sideEffects":false,"_nodeVersion":"22.23.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@opentelemetry/api":"^1.0.0"},"peerDependenciesMeta":{"@opentelemetry/api":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/commerce-sdk_0.18.6_1793398826402_0.8508850203588382"}}},"time":{"created":"2026-10-16T02:38:55.560Z","modified":"2026-10-30T22:20:26.668Z","0.0.0-stage":"2026-10-16T02:38:55.560Z","0.1.0":"2026-10-16T02:41:03.756Z","0.2.0":"2026-10-18T19:28:47.975Z","0.5.0":"2026-10-19T20:42:32.385Z","0.8.0":"2026-10-20T15:02:58.962Z","0.9.0":"2026-10-20T18:15:08.082Z","0.10.0":"2026-10-20T22:25:24.776Z","0.11.0":"2026-10-21T02:34:38.253Z","0.13.0":"2026-10-24T16:19:41.650Z","0.14.0":"2026-10-27T13:25:28.574Z","0.15.0":"2026-10-27T16:29:24.899Z","0.16.0":"2026-10-27T22:06:09.088Z","0.17.0":"2026-10-28T01:30:05.173Z","0.18.0":"2026-10-28T02:08:44.848Z","0.18.2":"2026-10-28T09:35:10.897Z","0.18.3":"2026-10-29T14:16:55.411Z","0.18.4":"2026-10-29T17:47:50.916Z","0.18.5":"2026-10-29T22:55:40.854Z","0.18.6":"2026-10-30T22:20:26.481Z"},"license":"SEE LICENSE IN LICENSE","homepage":"https://opencommerce.sh","keywords":["agentcard","agents","buy","tools","webhooks","purchases"],"description":"Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.","maintainers":[{"name":"pipeabello","email":"f@kasegu.llc"}],"readme":"# @agent-cards/commerce-sdk\n\nGive your agent one tool that buys for your shoppers at real stores, and tell each shopper what happened to their purchase in your agent's voice. The buy tool sends what the shopper says to Agentcard, and Agentcard finds the products, builds the cart and places the order once the shopper approves it. Agentcard then tells your server about each moment a shopper should hear about, such as a card saved, an order going through or an approval link about to expire, and the package hands you a message ready to post into that shopper's chat. Your server opens the connection to Agentcard, so you host no webhook endpoint.\n\n## Install\n\n```bash\nnpm install @agent-cards/commerce-sdk\n```\n\nThe package runs on Node 18 or later and has no dependencies.\n\n## Hear from Agentcard without webhooks\n\nCall `listen` once when your server starts. Your server opens one connection to Agentcard with your company credentials, and Agentcard sends every event for your company down it, so you need no public URL, no webhook secret and no signature check:\n\n```ts\nimport { AgentcardClient } from '@agent-cards/commerce-sdk';\n\nconst agentcard = new AgentcardClient({ clientId: process.env.AGENTCARD_CLIENT_ID ?? '', clientSecret: process.env.AGENTCARD_CLIENT_SECRET ?? '' });\nagentcard.listen({\n  onMessage: (shopperId, message) => postToChat(shopperId, message.text),\n  onEvent: (event) => console.log(event.type, event.data),\n});\n```\n\n`postToChat` stands for your own code. `onMessage` gets each message for one of your shoppers under your own id for them, the `externalUserId` you gave the buy tool, with the same ready-to-send `text` as `agentcardWebhook`: a card saved (`card_added`), an order placed, an approval about to expire, a delivery on its way. `onEvent` gets every other event Agentcard sends your company, such as `vault.card_stored`, `checkout_authorization.approved` or `transfer.completed`, as the same envelope a webhook endpoint would receive, with the same `id`. Without `onMessage`, `onEvent` gets every event. `AGENTCARD_EVENT_TYPES` lists every type, and `events: ['order.*', 'purchase.message']` keeps only the ones you name.\n\nThe listener keeps itself connected. It reconnects after a dropped connection, waiting longer after each failure up to 30 seconds, and reconnects when Agentcard sends no heartbeat for 45 seconds. Each reconnect resumes after the last event it handled, so nothing that happened while it was away is lost, and it skips an event it already handled. Agentcard keeps each event for the stream for 72 hours. Where the stream does not get through, the listener reads the same events every two seconds instead.\n\nEvents run one at a time, in the order Agentcard recorded them. The listener waits for your callback before it hands over the next event, and a callback that throws runs again, up to five times, before the listener passes the error to `onError` and moves on.\n\nA new process starts from the moment it connects. To resume where the last process stopped, pass a `cursor` store. After a resume, Agentcard hands over the last ten seconds of events again, in case one of them arrived late. The listener saves the cursor with the id of each event it handled in that window, so a new process skips the ones it already handled:\n\n```ts\nagentcard.listen({\n  onMessage: (shopperId, message) => postToChat(shopperId, message.text),\n  cursor: { load: () => redis.get('agentcard:cursor'), save: (cursor) => redis.set('agentcard:cursor', cursor) },\n});\n```\n\nOnce `onMessage` returns, the client keeps the message for that shopper's next `buy.turn`, and `turn.messages(history)` hands it to your model before the shopper's words, so the model knows the shopper saved a card or got an order. \"Tell the model what Agentcard told the shopper\" shows it. A message whose `advances` is true ends a step the shopper took outside the chat, such as saving a card: \"Take the next step once the shopper finishes one outside the chat\" shows how your agent moves on without waiting for their \"ok\".\n\n`listen` returns `{ ready, close }`: `ready` resolves once the listener reaches Agentcard, and `close()` stops it after the callback that is running returns. Run one listener per company and mode. Two listeners each hear every event, so with two, skip a `message.eventId` you already stored. Sandbox credentials hear sandbox events, live credentials live ones, and a shopper message is always live.\n\n`listen` needs a process that keeps running, such as a Node server, a worker or a container. On a host that ends each request after a few seconds, such as a serverless function, take the events at a webhook endpoint instead, as \"Hear from Agentcard at a webhook endpoint\" shows.\n\n## Give your agent the buy tool\n\nBuild one client with your company's credentials and one buy tool per shopper, then pass the tool to your agent as it is:\n\n```ts\nimport Anthropic from '@anthropic-ai/sdk';\nimport { AgentcardClient, appInstructions, buyTool } from '@agent-cards/commerce-sdk';\n\nconst agentcard = new AgentcardClient({\n  clientId: process.env.AGENTCARD_CLIENT_ID ?? '',\n  clientSecret: process.env.AGENTCARD_CLIENT_SECRET ?? '',\n});\n\nconst buy = buyTool({\n  agentcard,\n  externalUserId: shopper.id, // your own id for the shopper\n  sendLink: (link) => textShopper(shopper.id, link.url),\n});\n\nconst answer = await new Anthropic().beta.messages.toolRunner({\n  model: 'claude-opus-5-5',\n  max_tokens: 16000,\n  system: appInstructions({ markdown: true }),\n  tools: [buy],\n  messages: [{ role: 'user', content: 'two packs of AA batteries from Amazon' }],\n});\n```\n\n`shopper` and `textShopper` stand for your own code. The model calls `buy` with the shopper's words, shows the shopper the cart, and confirms the cart only after the shopper says yes.\n\nBuild the client once and keep it. Every shopper's tool shares the client's access token, and the client renews the token a minute before it expires. Keep each shopper's tool as well. Agentcard keeps each purchase between calls, so a tool built for every message buys the same way, but it sends the same product links again each time Agentcard shows the same products.\n\nThe model sends `ask`, `confirm`, `new_order`, `product_id` and `store_id`, and nothing else. A product link the shopper sends, such as a `buy.trychannel3.com` link, goes in `ask` exactly as sent, and Agentcard buys that exact product from it. Pass `deliveryAddress` when you already hold the shopper's address: the order goes there, and Agentcard never asks the shopper for it. The model can change neither the address nor the shopper.\n\n## Give your model Agentcard's instructions\n\n`appInstructions()` returns the system prompt Agentcard recommends for your model: what Agentcard can do for the shopper, in the words Agentcard's own buy agent uses, how to hand a request to the buy tool, and how to write for your app. Put it first in your system prompt, and add only what is about your app, such as its name:\n\n```ts\nconst system = [appInstructions({ markdown: true, textingStyle: true }), 'You are the shopping chat in Acme.'].join('\\n\\n');\n```\n\nPass `markdown: true` when your app shows the model's words as Markdown, so a shopper who asks for a table gets one; leave it out and the model writes plain text, with lists as `• ` lines. Pass `textingStyle: true` when your app is a chat that writes in lowercase, as you pass it to `buyTool`. The text ships inside the package and changes with each release; `APP_INSTRUCTIONS_VERSION` names the version you run.\n\n## Use the tool in any framework\n\nPass `buy` as it is. Each framework reads its own fields from the same object, so you pick no adapter:\n\n| Framework | Pass the tool | Who runs each call |\n|---|---|---|\n| Anthropic SDK, `client.beta.messages.toolRunner` | `tools: [buy]` | The tool runner. |\n| Vercel AI SDK 7 | `tools: { buy }` | The SDK. |\n| OpenAI SDK, OpenRouter's chat API, and any API that takes OpenAI's format | `tools: [buy.openai]` | Your loop, through `buy.handle`. |\n| OpenRouter's agent SDK, `callModel` | `tools: [toOpenRouterTool(buy, { tool, z })]` | The SDK. |\n\nIn your own loop, hand each tool call to `buy.handle` and give the model what it returns. Here the OpenAI SDK talks to OpenRouter's chat API:\n\n```ts\nimport OpenAI from 'openai';\n\nconst openrouter = new OpenAI({ baseURL: 'https://openrouter.ai/api/v1', apiKey: process.env.OPENROUTER_API_KEY });\nconst messages: OpenAI.ChatCompletionMessageParam[] = [{ role: 'user', content: 'two packs of AA batteries from Amazon' }];\nconst send = async () => (await openrouter.chat.completions.create({ model: 'anthropic/claude-opus-5.5', messages, tools: [buy.openai] })).choices[0].message;\n\nlet reply = await send();\nwhile (reply.tool_calls?.length) {\n  messages.push(reply);\n  for (const call of reply.tool_calls) {\n    if (call.type !== 'function') continue;\n    const content = await buy.handle(call.function.arguments).catch((error) => error.message);\n    messages.push({ role: 'tool', tool_call_id: call.id, content });\n  }\n  reply = await send();\n}\nconsole.log(reply.content); // the model's answer for the shopper\n```\n\n`buy.handle` takes the model's arguments as an object or as their JSON text, and returns the JSON text the model reads, with every link taken out. A call with input outside the schema rejects before anything reaches Agentcard. A call that fails rejects with a message that names no link, so the model reads `error.message` as it is.\n\nFor a framework with its own tool format, declare `buy.definition`, which holds the name, the description and the input schema, and run the same three lines for each tool call.\n\nOpenRouter's agent SDK accepts only tools that its own `tool` builds from a zod schema, so that SDK keeps an adapter. Pass your own `tool` and `z`, and the package still installs no dependencies:\n\n```ts\nimport { OpenRouter, tool } from '@openrouter/agent';\nimport { z } from 'zod';\nimport { toOpenRouterTool } from '@agent-cards/commerce-sdk';\n\nconst result = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY }).callModel({\n  model: 'anthropic/claude-opus-5.5',\n  input: 'two packs of AA batteries from Amazon',\n  tools: [toOpenRouterTool(buy, { tool, z })],\n});\nconsole.log(await result.getText());\n```\n\n`toAnthropicTool(buy)` is no longer needed, and returns `buy` itself, so code that still calls it keeps working.\n\n## Send the shopper each link\n\nA purchase needs a link at three moments: the shopper approves the purchase on an approval page, a new shopper adds a card on a Vault page, and a shopper signs in to a store's own account on its login page before Agentcard can buy there. Each link's `kind` says which: `approval`, `vault` or `store_login`, and a `store_login` link names the store in `store`. The tool hands each link to `sendLink` and waits for it, so the shopper holds the link before the model answers. The model reads `link_sent: true` and never the link itself, because a tool runner puts each answer straight into the model's context, and a model that holds a link writes it into the chat.\n\nThe tool also hands `sendLink` a `product` link for each product a search finds, up to eight per answer. The link carries the product's page at its store in `url`, the product's name in `title`, its price in `price`, such as `$12.99`, or `from $10.69` for a product priced by a size or another choice the shopper makes, such as a burger whose patty count sets its price, Agentcard's id for it in `productId`, what taking it does in `action` (`reserve` for a restaurant table, `book` for a flight, room, class or ticket, `buy` for anything else, so a button can say Reserve instead of Buy this), its picture in `imageUrl`, or null when the store sent none, and every photo of the product in `images`, `imageUrl` first and at most eight, so a card can show the others as thumbnails that swap the main picture. `images` holds one entry for a product with one photo and none for a product with none. The link names the store that sells the product in `store`, such as `Walmart`, and the store's own website in `storeDomain`, such as `walmart.com` or `jadeyoga.com`, or null when Agentcard knows none, such as a restaurant's: show `storeDomain` on the card as where the product comes from, never the host of `url`, which can be a tracking link. Every price the tool writes, in a link or in the model's view, uses the currency Agentcard names for the cart or the product, in that currency's own minor units: `1331` is `$13.31` in USD, `CA$13.31` in CAD and `¥1,331` in JPY. A price whose currency Agentcard does not name shows with no symbol. The link arrives beside the reply, and you decide how to show it: as a card, in a list, or as a text with the URL. Each product gets its own link, so the three dishes a restaurant's reply offers are three cards, though they share the store's one page. A flight has no page at a store, so each flight a search finds is a `product` link whose `url` is null, with the airline, the route and its times in `title`: show it as a card with no link to open, and hand its `productId` back as the shopper's pick. The model reads `product_links_sent` and never a URL. The tool's description tells it that the shopper already sees those products as cards, so its reply never lists them again by name or price: it writes one short line, such as which one they want, and a shopper who asks for links hears that the links are there. When a later answer in the conversation only stands beside the same products, as a cart answer does, the tool sends none of their links again. When a later turn's reply presents them again, as the answer to a repeated ask does, the tool sends their links again, so every product the reply names arrives with its link. A product link your `sendLink` throws on counts as not sent, and the call goes on.\n\n`productId` holds no link: it is the same `product_id` the model reads for that product, and the page is `url`. An answer that only adds a product the shopper picked lists that product alone, so it sends no card for a product nobody offered on that turn, and the pages the search already sent still count as sent on the answers after it.\n\nWithout `sendLink`, `result.links` still carries each Vault, approval and store login link for your code, each product in `result.products` carries its `url`, and the model still never reads one.\n\n## Open each step in a pop-up, and close it when it is done\n\nA Vault, approval or store login link is a step the shopper takes outside the chat. Each one carries a stable `id`, such as `vault_1x9k2qd`: the same every time the same link is handed over, on your server and in the browser, with no part of the URL in it, so it is safe as a DOM key or in a log. `actionLinkId(link)` reads it from a link that has none.\n\nEach step ends with a shopper message: `actionLinkOutcome(link, message)` says how a message ended the step, or null when it left it open. `ACTION_LINK_ENDINGS` is the whole table:\n\n| Link | `completed` | `declined` | `failed` | `expired` |\n| --- | --- | --- | --- | --- |\n| `vault` | `card_added` | | | `card_link_expired` |\n| `store_login` | `store_connected` | | `store_connect_failed` | `store_connect_expired` |\n| `approval` | `order_placing`, `order_placed`, `order_not_placed_yet`, `order_unconfirmed`, `order_confirmed`, `order_failed`, `payment_declined` | `approval_declined` | | `approval_expired` |\n\nA reminder, such as `card_link_unfinished` or `approval_expiring`, leaves the step open. An approval is `completed` once the shopper approved, even when the order then failed or the payment was refused: the approval page has nothing more to do, and the message tells the shopper what happened. A message whose facts name another link of the same kind (`facts.approvalUrl`, `facts.cardLinkUrl`) leaves this one open, and so does one about another store: a store login link names its store in `store`, and so does an approval link when the answer names the cart's store, so DoorDash's `store_connected` (`facts.merchantName: 'DoorDash'`) never ends a Locale sign-in the shopper has open beside it.\n\nIn the browser, `actionWindows` from `@agent-cards/commerce-sdk/browser` opens each step in a pop-up window centered over the chat, so the shopper never leaves it, and closes the pop-up the moment the message that ends the step arrives. The browser entry imports no Node module, so any bundler takes it:\n\n```ts\nimport { actionWindows } from '@agent-cards/commerce-sdk/browser';\n\nconst windows = actionWindows({\n  onEnded: (step, outcome) => markStepDone(step.id, outcome),\n  onClosed: (step) => keepOfferingStep(step.id),\n});\n\n// The link's own click handler, so the browser counts the tap as the reason for the pop-up. When the\n// browser blocks it, `open` returns null and the link opens the way it would have, as a new tab.\nstepLink.addEventListener('click', (event) => {\n  if (windows.open(link)) event.preventDefault();\n});\n\n// Each shopper message your server forwards from `listen` or the webhook, with its `kind` and `facts`.\nonShopperMessage((message) => windows.settle(message));\n```\n\n`markStepDone`, `keepOfferingStep` and `onShopperMessage` stand for your own code. `settle` closes each open pop-up whose step the message ends and returns `[{ step, outcome }]`. A pop-up the shopper closes before the step ends reaches `onClosed`, checked every 500 milliseconds (`pollMs`): the step is still open, so keep its link on screen, and a tap opens it again. Tapping a step whose pop-up is open brings that window to the front instead of opening a second one. A phone's browser opens the pop-up as a tab, and `settle` closes that tab the same way, since the chat opened it. The pop-up is 480 by 760 pixels by default (`width`, `height`), kept inside the screen. It keeps its opener on purpose: a window opened with `noopener` hands back no handle, so the chat could neither close it nor tell when the shopper closed it. `dispose()` stops watching and leaves every pop-up open, so a chat that remounts never shuts the page a shopper is typing a card into.\n\n## Keep the answer when the shopper's connection drops\n\nA phone that loses its connection while a reply streams back would show the shopper an error, though the turn finished on your server. Serve the turn with `turnStream` and read it in the browser with `streamTurn`, and the shopper gets the answer anyway. On your server:\n\n```ts\nimport { readTurn, turnStream, isTurnId } from '@agent-cards/commerce-sdk';\n\n// POST /chat: the browser names the turn in `x-turn-id`.\nconst turnId = request.headers.get('x-turn-id');\nif (!isTurnId(turnId)) return Response.json({ error: 'Name the turn.' }, { status: 400 });\nconst { stream, finished } = turnStream({ store, key: `${shopperId}:${turnId}`, run: (send) => runTurn(send) });\nwaitUntil(finished);\nreturn new Response(stream, { headers: { 'content-type': 'text/event-stream' } });\n\n// GET /chat/turn?id=...: the turn's record, for the browser to pick up where its stream stopped.\nreturn Response.json(await readTurn(store, `${shopperId}:${id}`));\n```\n\n`store` is yours, such as Redis: `load(key)` and `save(key, record, ttlSeconds)`. `runTurn` stands for your agent's turn, and `send(event, data)` takes each event the chat shows, the last one included, such as `done`. The turn runs to its end after the browser leaves, and `finished` resolves once its record is saved: hand it to your host's `waitUntil`. The record is kept for ten minutes (`ttlSeconds`). Put your shopper's id in the key, so no shopper reads another's turn. When one turn at a time runs per shopper, answer a message sent during a turn with a 409 whose body names that turn, `{ \"error\": \"...\", \"turn_id\": \"...\" }`.\n\nIn the browser:\n\n```ts\nimport { streamTurn, readTurnResponse } from '@agent-cards/commerce-sdk/browser';\n\nconst { refused } = await streamTurn({\n  start: (turnId) => fetch('/chat', { method: 'POST', headers: { 'x-turn-id': turnId }, body }),\n  read: (turnId) => fetch(`/chat/turn?id=${turnId}`).then(readTurnResponse),\n  onEvent: (event, data) => show(event, data),\n});\n```\n\n`onEvent` hears each event once, in order. When the stream drops, before its first event or after it, `streamTurn` reads the turn's record every 1.5 seconds (`pollMs`) and hands over the events the stream did not carry, until the turn's last one. A 409 that names a running turn waits for that turn's answer the same way. Any other refusal comes back in `refused`, the response, for you to show its error. A record that never appears within 15 seconds (`startWaitMs`) means the message never reached your server, and `streamTurn` throws the connection's error.\n\n## Answer each shopper message in its own turn\n\nA shopper can send a second message before the first is answered. The `sendLink`, `onWorking` and `onResult` you pass to `buyTool` hear every call, whichever message the call answers, so a callback that hands each link to \"the message running now\" gives the first message's cards to the second. Open a turn for each message instead, and pass the turn to your model in place of the tool:\n\n```ts\nconst buy = buyTool({ agentcard, externalUserId: shopper.id }); // one per shopper, kept\n\nasync function onShopperMessage(message: string) {\n  const turn = buy.turn(message, { onReaction: (emoji) => reactToShopperMessage(shopper.id, emoji) });\n  const runner = new Anthropic().beta.messages.toolRunner({\n    model: 'claude-opus-5-5',\n    max_tokens: 16000,\n    tools: [turn],\n    messages: turn.messages(history),\n  });\n  const answer = await runner;\n  history = runner.params.messages;\n  return { answer, links: turn.links, carts: turn.results.at(-1)?.carts ?? [] };\n}\n```\n\n`history` stands for the shopper's earlier messages. `turn.messages(history)` is the history, then what Agentcard told the shopper that the history doesn't hold yet, then `message`. Every call the model makes through `turn` belongs to that message alone:\n\n- `turn.links` holds each link the turn's calls handed over, in order: the Vault, approval and store login links, each product's store page, and each store card's page. The model reads that each one went out, so send them with the reply. Pass `sendLink` to `buy.turn` as well to send each one the moment the tool hands it over, such as down a server-sent event stream. A link your `sendLink` throws on stays out of `turn.links`.\n- `turn.results` holds the whole answer of each call, and an `onResult` passed to `buy.turn` hears each one as it arrives.\n- With `onReaction`, `buy.turn` puts a 👀 on a message that starts a search at once, before your model runs, and `turn.reaction` holds it. With only `onWorking`, it sends the text reply `buy.instantAck` would return, or the one your `ack` function writes, and `turn.ack` holds that text. You never call `instantReaction` or `instantAck` yourself. A slow call of the turn acknowledges through the same callback.\n- An `onProgress` passed to `buy.turn` hears only that turn's stages.\n- `turn.agentcardMessages` holds each message `agentcard.listen` or `agentcardWebhook` posted into this shopper's chat that the model has not read yet, and `turn.messages(history)` hands them to the model.\n\nA callback you leave out of `buy.turn` falls back to the one the tool was built with, so a tool whose `sendLink` texts the shopper keeps texting, and `turn.links` lists the same links. The turn is the tool, with the same name, schema and methods, so pass it to every framework the way you pass `buy`: `tools: [turn]`, `tools: { buy: turn }`, `tools: [turn.openai]` with `turn.handle`, or `toOpenRouterTool(turn, { tool, z })`. `turn.ack`, `turn.reaction`, `turn.links` and `turn.results` stay out of the tool's JSON, so a tool runner sends the API the same fields. Build the tool once per shopper and open a turn from it for each message: the turns share the shopper's conversation, so a card a shopper already holds from an earlier turn is not sent again.\n\nA call made on `buy` itself still works as before: it belongs to the turn the tool reads from its timing, and its links go to the tool's `sendLink`.\n\n### Show Agentcard's reply as written\n\nMost answers only ask the shopper something: which product, which size, which store, or a yes to a cart's total. Agentcard's reply already says that, so a second model call that rewords it costs the shopper one more model round trip and changes nothing. Pass `replyAsWritten: true`, to `buyTool` for every turn or to `buy.turn` for one, and `turn.replyAsWritten` holds Agentcard's reply, with every link taken out, whenever the turn's last answer only asks. Show it and end the turn without calling your model again:\n\n```ts\nconst turn = buy.turn(message, { replyAsWritten: true, onMessage: (text) => sendText(shopper.id, text) });\nconst runner = new Anthropic().beta.messages.toolRunner({ model: 'claude-sonnet-5-5', max_tokens: 16000, tools: [turn], messages: turn.messages(history), stream: true });\nlet written: string | null = null;\nfor await (const stream of runner) {\n  written = turn.replyAsWritten;\n  if (written !== null) {\n    stream.abort(); // the reply says it already: no second model call\n    break;\n  }\n  const paragraphs = turn.messageStream();\n  stream.on('text', (delta) => paragraphs.push(delta));\n  await stream.done();\n  await paragraphs.end();\n}\nif (written !== null) await turn.say(written);\nhistory = written !== null ? [...runner.params.messages, { role: 'assistant', content: written }] : runner.params.messages;\n```\n\nAn answer whose next step is a link the turn handed over gets the same short line every time, whoever wrote the reply, so sending the card link, the sign-in link or the approval link takes no model either: `add your card to place the order`, `sign in to DoorDash to place your order`, or `approve the payment to place your order (up to $17.89)`, with the most the shopper can be charged in the parentheses. Show it with `turn.say()` and the link follows it. When the shopper's own message just put the cart together, a line about the cart comes first, as its own message (`1 Chicken Salad from Souvla, $17.43`); after a yes or a saved card, the ask is the whole message. `stepAsWritten(result)` returns that line for one answer, or null when the answer is not a link step, its link did not go out, a card or approval step has no cart to place, or the answer also showed products.\n\nAny other answer, such as an order placed or a refusal, leaves `turn.replyAsWritten` null, and your model words it. So does a line the tool writes itself for your model, such as the note that the cart changed or a `buy.nextStep` turn's ask for the shopper's yes: only a reply Agentcard sent goes out as written. `replyAsWritten(result)` applies the same rule to one answer, for a loop that reads `turn.results` itself. Leave the option off to have your model write every answer.\n\nEvery list in the reply comes as bullet lines that start with `• `, the choices Agentcard writes one per line with no marker included, such as the breads after `which bread do you want?`. A numbered list of the answer's products or stores keeps its numbers, since the shopper may answer `number 3`. Each message `onText` hears comes the same way. Pass `textingStyle: true`, to `buyTool` or `buy.turn`, to get the reply and those messages in a chat's texting style as well: lowercase at the start of each sentence and for \"I\", no markdown and no spaced dashes, with the bullets kept. `textingStyle(text)` and `asBullets(text)` do the same to any text.\n\nAn answer that asks the shopper to choose, such as a sandwich's bread, a shirt's size or a store's own size question, carries `result.choice`: each group with every value, its option id and its extra price in `price_delta_cents`. The reply shown as written lists each value on its own `• ` line under the question, with its extra price, and so does one more `onText` message when the streamed reply named the values inside a sentence. `withChoice(text, result.choice)` lists them under any text of your own.\n\n### Let Agentcard answer shopping first\n\nSend the shopper's message to Agentcard before your model runs, and run your model only when the message is yours:\n\n```ts\nconst turn = buy.turn(message, {\n  onItem: (item) => (item.kind === 'text' ? sendText(shopper.id, item.text) : sendCard(shopper.id, item.link)), // your code\n});\nif (await turn.handled()) {\n  // A newer message from the shopper stopped this turn: that message's turn answers and keeps the exchange.\n  if (turn.stopped) return;\n  // Agentcard answered the shopper: keep the exchange, so your model reads it on the next message.\n  const said = turn.items.flatMap((item) => (item.kind === 'text' ? [item.text] : [])).join('\\n\\n');\n  history = [...turn.messages(history), { role: 'assistant', content: said }];\n  return;\n}\n// Otherwise run your model on turn.messages(history), as before.\n```\n\nAgentcard answers a request to buy or book, with or without a verb (`Printer paper, one ream`), a pick of what it just showed (a card's tap, `the second one`, `1 and 3`), an answer to its question (the address, a code, `medium`) and a yes to a total. When its reply only asks the shopper something, the turn sends it through `onItem`, after the cards and the card, sign-in or approval link it handed over, and `handled()` resolves `true`: no model call before the search, and none after it.\n\nEvery other message comes back from Agentcard as yours in about 0.1 to 0.2 seconds, with no search, and `handled()` resolves `false`: small talk, a question, a change of mind such as `no` or `wait`, and anything about the account or an order. An answer your model has to word, such as an order placed or a refusal, resolves `false` too, and `turn.messages(history)` hands your model that answer with the shopper's message, so it words it and calls the tool no second time.\n\n`handled()` sends one call, once, and a second call resolves as the first did. A turn `buy.nextStep` opened resolves `false` and sends nothing: take it as \"Take the next step once the shopper finishes one outside the chat\" shows.\n\nYou no longer need `direct` or `replyAsWritten` for this. They still work as they did: `direct: true` sets `turn.direct` to the call the tool's own rule reads in a message (`directCall(text, context)`), and `replyAsWritten: true` sets `turn.replyAsWritten`, for an app that sends the call itself. An app that never calls `handled()` sends nothing until its model calls the tool.\n\n### Hand the app the turn in order\n\nA turn reaches the shopper as messages and links that interleave: the instant reply, the cards a search found, then your model's words about them. Pass `onItem` to `buy.turn`, and the turn hands your app all of them as one sequence, one item at a time, in the order they happened. Show each item below the one before it:\n\n```ts\nconst turn = buy.turn(message, {\n  onItem: (item) => (item.kind === 'text' ? sendText(shopper.id, item.text) : sendCard(shopper.id, item.link)),\n  onTyping: (typing) => showTyping(shopper.id, typing),\n});\nconst runner = new Anthropic().beta.messages.toolRunner({ model: 'claude-opus-5-5', max_tokens: 16000, tools: [turn], messages: turn.messages(history), stream: true });\nfor await (const stream of runner) {\n  const paragraphs = turn.messageStream();\n  stream.on('text', (delta) => paragraphs.push(delta));\n  await stream.done();\n  await paragraphs.end();\n}\n```\n\n- A `text` item is the instant reply, or a message your model wrote through `turn.messageStream()` or `turn.say(text)`. A `link` item is each link the tool hands over, with the fields `sendLink` would get. A message of Agentcard's that `onText` takes holds its place in `turn.items` as a `text` item too, and reaches `onText` alone.\n- Each message goes out the moment it is ready. Pass `pace: true` to space them like someone texting: each one then waits until `typingDelay` of it has passed since the item before it went out, 300 ms plus 12 ms a character, at most 1.5 seconds. Time your model spent writing counts toward the pause, so a slow model gets no added wait, and links never wait. `onTyping` hears `true` when a pause starts and `false` when its message goes out. A function returns your own pause in milliseconds.\n- With `onItem`, the turn sends no link to a `sendLink` and no instant reply to an `onWorking`, so a tool built with those for other turns sends nothing twice. Passing `onItem` beside `sendLink` or `onWorking` to the same turn throws.\n- `turn.items` holds every item that went out, in order, so an app that answers the whole turn at once returns it as is. A turn without `onItem` keeps `turn.items` as well, unpaced.\n- A step link, the `vault`, `approval` or `store_login` page the shopper opens to go on, comes after the message that asks for it: the turn holds it until your model's next message stream ends (or `turn.say` is called), then sends it right after that message, so the shopper reads \"add your card to place the order\" and then taps. Product and store cards go out the moment the tool hands them over. A held link also goes out when the turn's next call starts, or after 20 seconds, so a model that writes nothing still sends it. `turn.say` and the stream's `end` resolve once the held links went out too, and reject when one failed to send, so your app never answers without a link the shopper needs; a link that failed to go out at the next call or the 20 seconds rejects the next reply that ends.\n- Without `onItem`, pass `onMessage` beside `sendLink`, and write the model's text through `turn.messageStream()`: `onMessage` hears each message, paced, and `sendLink` hears each step link after the message that asks for it. An app that streams the model through the package's own `messageStream` gets each link the moment the tool hands it over, before the words about it.\n\n## Keep one purchase per chat\n\nA shopper who writes to your agent in several chats at once, such as group chats or threads, would otherwise continue one purchase from all of them. Build one tool per shopper and chat, and name the chat with `threadId`, your own id for it. Agentcard then keeps a purchase per chat: each chat's carts, questions and approvals stay in that chat, while the shopper keeps one Vault card, one store sign-in and one address book.\n\n```ts\nconst buy = buyTool({ agentcard, externalUserId: shopper.id, threadId: chat.id }); // one per shopper and chat\n```\n\nA message about one chat's purchase carries that chat as `threadId`, so post it into that chat. One about the shopper alone, such as a saved card, carries `threadId: null`. A chat's tool takes a next step only for its own chat's messages and the shopper's own, and a tool built without `threadId` only for purchases opened under no thread and the shopper's own.\n\n## Choose how long a reply waits for stores\n\nA search that asks several stores writes its reply once the stores answered or a wait ran out. Choose that wait with `storeWaitMs`, and choose with `lateResults` what happens to a store that answers after the reply:\n\n```ts\n// A streaming chat: cards show as each store answers, the reply waits up to 25 s (99.7% of stores' first products), and a later store's cards stream below it.\nconst buy = buyTool({ agentcard, externalUserId: shopper.id, storeWaitMs: 25000, lateResults: 'stream' });\n// A texting app: the reply waits up to 20 s (96% of stores' first products) and is the turn's last word.\nconst sms = buyTool({ agentcard, externalUserId: shopper.id, storeWaitMs: 20000, lateResults: 'hold' });\n```\n\nAgentcard ends every store search at 30 s, so a `storeWaitMs` above `30000` waits no longer than `30000` does.\n\n- `lateResults: 'stream'` sends a late store's cards after the reply, in the same turn, the way a slower hotel supplier's cards come: to `sendLink`, `onProducts` and `onItem`, with the one message that says what they added. The turn's `onResult` lists them in `result.products` after the answer's own.\n- `lateResults: 'hold'` keeps a late store's cards out of the turn, so a texting app never sends a card after the reply.\n- `buy.turn(message, { storeWaitMs, lateResults })` sets them for one turn, and each one left out keeps the tool's. An app that calls `client.buy` itself sends `store_wait_ms` and `late_results`.\n- Left out, the tool sends neither, and Agentcard keeps its own wait. A wait that is not a whole number of milliseconds, 0 or more, throws a TypeError before any call.\n\n## Tell the model what Agentcard told the shopper\n\nAgentcard posts messages into the shopper's chat between turns, through `listen` or the webhook: `Your Visa ending 3132 is saved, so you're ready to check out.`, an order placed, an approval about to expire. The shopper reads them, so your model has to know them too. A model that never saw `card_added` answers \"ok lets checkout\" with \"did you save your card?\" and never calls the tool.\n\nBuild the listener and every buy tool on the same `AgentcardClient`. Then pass `turn.messages(history)` as the model's messages, and save what the run ends with as the next history:\n\n```ts\nconst agentcard = new AgentcardClient({ clientId, clientSecret });\nagentcard.listen({ onMessage: (shopperId, message) => postToChat(shopperId, message.text) });\n\nconst turn = buyTool({ agentcard, externalUserId: shopperId }).turn(message);\nconst runner = anthropic.beta.messages.toolRunner({ model: 'claude-opus-5-5', max_tokens: 16000, tools: [turn], messages: turn.messages(history) });\nawait runner;\nhistory = runner.params.messages;\n```\n\nHow it works:\n\n- Once your `onMessage` returns, the client keeps the message for that shopper. A message whose `onMessage` threw every time never reached the chat, so the client does not keep it.\n- `buy.turn` reads the messages kept for its shopper when it opens. `turn.agentcardMessages` holds them, oldest first.\n- `turn.messages(history)` returns a new array: `history`, then Agentcard's `text` as the assistant's words, then the shopper's message as `{ role: 'user', content: message }`. The chat showed Agentcard's message in your agent's voice, so the model reads it as its own. Every link is taken out of the model's copy, as `forModel` takes them out of an answer, and the message `onMessage` got keeps them.\n- A message stays kept until a history you pass to `turn.messages` holds it, and then the client forgets it. So when a turn fails and you keep the history you had, the next turn hands the message to the model again. Once you saved a history that holds it, no turn hands it over a second time.\n- When the last message in `history` is the assistant's plain text, Agentcard's words join that message, so no provider reads two assistant messages in a row. That covers a string, or `text` parts as the Anthropic API, the Vercel AI SDK and OpenAI's chat completions write them. After anything else, such as a tool result, a tool call or an OpenAI Responses item, they come as an assistant message of their own. `history` itself is never changed.\n- The Anthropic SDK's `messages`, the Vercel AI SDK's `messages`, OpenAI's chat completions `messages` and the Responses API's `input` all take what it returns.\n\nWith a webhook, pass the client to the handler: `agentcardWebhook({ secret, agentcard, onMessage })`. For a message you deliver some other way, call `agentcard.delivered(shopperId, message)` once it reaches the chat. The client keeps each message once per `eventId`, so a message both the listener and the webhook carry reaches the model once.\n\nThe messages live in the client's memory, at most 20 per shopper. So the listener, or the webhook, and the turn have to run in one process on one client. When your listener runs in one process and your model in another, such as a serverless chat route, keep each message where your chat history lives as `onMessage` delivers it, as an assistant message, and the model reads it from the history.\n\n## Take the next step once the shopper finishes one outside the chat\n\nSome steps happen outside the chat: the shopper saves a card from the Vault link, signs in to DoorDash from the sign-in link, or declines the approval. Agentcard tells your server the moment each one ends, and its message reads like `Your Visa ending 4242 is saved, so you're ready to check out.`. Posted as is, it leaves the shopper to say \"ok\" or \"done\" before anything moves. Take the next step for them instead: when `message.advances` is true, open `buy.nextStep(message)` and run your model on it, and post the model's answer in place of `message.text`:\n\n```ts\n/** Each shopper's model runs, in order: the chat's own turns should wait on it too. */\nconst runs = new Map<string, Promise<void>>();\n\nagentcard.listen({\n  onMessage: (shopperId, message) => {\n    const step = buyFor(shopperId).nextStep(message);\n    if (!step) return postToChat(shopperId, message.text);\n    // Run it without awaiting, so the listener moves on to the next event. One shopper's runs go in order, after\n    // their last one, so an older run never writes its history over a newer one.\n    // A turn that fails is released, so its text reaches later turns and a redelivery can take the step again.\n    const run = (runs.get(shopperId) ?? Promise.resolve()).then(() => runModel(shopperId, step)).catch(() => {\n      step.release();\n      agentcard.delivered(shopperId, message);\n      postToChat(shopperId, message.text);\n    });\n    runs.set(shopperId, run);\n  },\n});\n\nasync function runModel(shopperId: string, turn: BuyToolTurn) {\n  const runner = anthropic.beta.messages.toolRunner({ model: 'claude-opus-5-5', max_tokens: 16000, tools: [turn], messages: turn.messages(histories.get(shopperId)) });\n  const answer = await runner;\n  histories.set(shopperId, runner.params.messages);\n  postToChat(shopperId, textOf(answer), turn.links);\n}\n```\n\n`buyFor` stands for the buy tool you keep for each shopper, and `textOf` for the text of the model's answer. The turn is a `buy.turn` in every way but one: no shopper wrote anything, so `turn.messages(history)` ends with the event, marked as written by the system, and the instruction to take the next step now in one short message, never \"you're all set, what's next?\". The shopper reads one message that does the next thing:\n\n| The shopper finished | The next message |\n| --- | --- |\n| Saving a card, after their yes stopped for it | The approval link: `approve the payment to place your order (up to $19.02)` |\n| Saving a card, after picking the product and answering only the checkout's questions | The approval link: `approve the payment to place your order (up to $221.00)` |\n| Saving a card, with no yes and no pick standing | The total and the ask for the yes: `your Souvla chicken salad comes to $17.43 with fees. should i go ahead and place the order?` |\n| Signing in to the store, with a card still to add | The add-card link: `next, add a card with the link i sent. it works for about 24 hours.` |\n| Signing in to the store, with a card on file | The total and the ask for the yes, or the approval link after a yes that stopped for the sign-in |\n| Signing in or saving a card, after a yes, when the store priced its fees and tax in since | The new total and the ask for the yes, with no link: `The cart changed after your yes: it comes to $17.89 with tax and shipping now. Nothing was paid. Say yes to pay $17.89.` |\n| Declining the approval | `you declined the payment, so you haven't been charged. your chicken salad is still in the cart, so just say yes if you want a new approval link, or tell me what to change` |\n\nWith `direct` and `replyAsWritten` on the tool, a step needs no model when its answer is a link: send `step.run(step.direct.input)` first, and when `step.replyAsWritten` is set, post it, with `step.links`, in place of the model's answer. When it is null, as for the ask for a yes, run your model as above.\n\nThe turn moves the purchase only up to the shopper's own decision, and the tool holds it there whatever the model calls:\n\n- No call of the turn sends an ask to Agentcard, which could read the model's words as the shopper's go-ahead. Each call reads where the purchase stands and answers with the next step: the card link the sign-in held back, or the cart and the ask for the shopper's yes.\n- A confirm goes in only for the yes the shopper already gave in the chat, such as \"lets place it\", when that confirm stopped for the card or the sign-in they just finished, and the shopper is never asked for that yes again. It goes on past each step, the sign-in and then the card, as long as the cart holds the same items, in the same quantities and at the same prices, at the same store. Each confirm names the cart's hash as it stands, and in `carried` the hash of the cart the shopper said yes to: Agentcard pays only that cart, so a total that moved because the store priced its fees, tax or delivery in comes back with the new total and the ask for the shopper's yes, and nothing is paid. A cart whose items, quantities or store changed, a shopper message after the yes that is not a plain go-ahead, such as \"wait, make it two\", and a declined approval each take the yes back, and the shopper is asked again. Any other confirm the model sends is refused by the tool, and nothing reaches Agentcard.\n- A shopper who picked what is in the cart, by tapping a product's card or asking to buy it, and since answered only the checkout's questions (an address, a phone number, a name, an email, a yes to an address read back to them) or said a plain go-ahead, gave the same go-ahead: saving the card or signing in to the store confirms that cart by its hash as it stands, with no ask for a yes (`yes_carried.picked`). The confirm names in `carried` the cart the chat showed, and a cart the store priced again since comes back with its total and the ask for a yes. A cart whose items, quantities, item prices or store changed since the pick, any other message, such as \"actually wait\" or a question, and a declined approval take it back.\n- The approval in the Vault is still the shopper's: the confirm sends the approval link, which names the most they can be charged, and the order goes in only once they approve it.\n- A shopper who was not connected yet when they asked gets their own first ask run, in their words, once their card is saved.\n\n`buy.nextStep` returns null when there is no step to take: a message whose `advances` is false, such as `order_placed`, whose `text` is already the whole message; a message for another shopper, or one whose link closed; a message it already took a turn for; and one that arrives while a call for the shopper's own message is still running, since that call's answer tells the model where the purchase stands. Post `message.text` then. `NEXT_STEP_KINDS` lists the kinds that advance: `card_added`, `store_connected` and `approval_declined`. Once `buy.nextStep` opens a turn, the client never hands the message's text to a later turn as words the shopper read, since they never read it. When your agent cannot finish the turn, call `step.release()` before you post `message.text`: the text then reaches later turns once `agentcard.delivered` records it, and a redelivery of the event opens a turn again.\n\n## Add the exact product the shopper picks\n\nEach product in the model's view carries a `product_id`, Agentcard's id for it with no link in it. When the shopper picks one of those products, by its name, its place in the list or a tap on its card that sends its title, the model passes that `product_id`, and Agentcard adds exactly that product from the products it showed, with no new search. Your app sends no id of its own: a \"Buy this\" button that sends the shopper's words, such as `I'll take the KODAK AA Alkaline Batteries (24 Pack) ($13.49)`, is enough, because the model reads the `product_id` beside that name in its last result. Keep each tool result in the model's history, as a tool runner does, so the model still holds those ids on the shopper's next message. Your own code can pick too: a card's button can call `buy.answer` with the link's `productId` as `product_id`, and Agentcard adds that product.\n\n`result.pick` says what happened: the product's id, and `in_cart`, whether the cart now holds it. The model reads the same `pick` in its view, by the `product_id` it sent. A pick the cart does not hold names no next step, so the model tells the shopper what Agentcard said rather than asking for a card or a yes for an older cart. A product Agentcard no longer holds, because the products are more than 15 minutes old or a newer search replaced them, adds nothing, and the model reads that it should search again with the shopper's words.\n\n## Show the stores the shopper picks from\n\nA delivery order often starts with a choice of store: the shopper asks for a taco, and Agentcard answers with the taquerias near them that deliver. Each store the reply names reaches `sendLink` as a `store` link, up to eight per answer, in the order the reply names them. The link carries the store's page at the merchant in `url`, its name in `title`, Agentcard's id for it in `storeId`, the delivery estimate in minutes in `etaMinutes`, or null when the store showed none, and the picture the store's card shows at the merchant in `imageUrl`, or null when it shows none. Show it as a card with the picture and an \"Order here\" button. `result.stores` carries the same stores for your code, each with its `url` and `linkSent`.\n\nThe model reads each store in `stores` by its `store_id`, name and `eta_minutes`, never its page, and `store_links_sent` says how many store pages the shopper holds. When the shopper picks a store, by its name, its place in the list or a tap on its card, the model passes that `store_id`, and Agentcard selects exactly that store before its agent answers, so the products it finds next are from that store. A card's button can call `buy.answer` with the link's `storeId` as `store_id`. A shopper who answers only with a place in the list, such as `the second one` or `2`, picks the store at that place in the last answer's list, whether or not the model passed the id. A store pick starts no search, so it gets no instant reply: a card tap that sends `Order from Tacos El Grullense`, the store's name alone or with `please`, and `order here` or `this place` all read as a pick of a store the last answer listed. A dish beside the store's name, as in `order tacos from el farolito`, is a search.\n\n`result.store_pick` says what happened: the store's id and name, and `selected`, whether the merchant took the selection; when it did not, Agentcard's agent selects the store itself. The model reads `store_pick` by the `store_id` it sent. A store Agentcard no longer holds, because the stores are more than 15 minutes old or a newer search replaced them, selects nothing, and the model reads that it should search again with the shopper's words.\n\nThe tool sends each store page once for the calls the model makes in one turn. A later turn whose reply presents the stores again gets their pages again, so every store the reply names arrives with its card. A store link your `sendLink` throws on counts as not sent. Agentcard lists stores only for an answer whose reply presents them as a choice: a turn that searched stores on its way to a menu, or one that shows a cart, lists none.\n\n## Tell the shopper you are on it\n\nA first search can take Agentcard most of a minute. Pass `onReaction`, and the shopper sees a 👀 on their own message while Agentcard looks, the way a friend reacts to a text before answering it. Show it as a tapback on the shopper's bubble:\n\n```ts\nconst buy = buyTool({\n  agentcard,\n  externalUserId: shopper.id,\n  sendLink: (link) => textShopper(shopper.id, link.url),\n  onReaction: (emoji) => reactToShopperMessage(shopper.id, emoji), // emoji is always '👀'\n});\n```\n\nA reaction is the default acknowledgement. It names nothing the shopper said, so it never reads a request back wrong, and the chat holds only real answers. Each message gets at most one 👀:\n\n- A message that starts a search gets it the moment `buy.turn` opens, before your model runs.\n- A pick of a product or a store the shopper saw, an address or other details, an answer to a question such as `yes`, `2` or a code, a step toward checkout such as `ok lets checkout`, and an acknowledgement such as `its ok` get none when the turn opens, because Agentcard answers them fast.\n- A call that Agentcard has not answered within 1 second puts the 👀 on a message that has none yet: a slow `yes`, a pick, or a confirm that is still placing the order. It sends no text.\n- A turn that runs long, even past a minute, still gets no text line. A search often takes 10 to 40 seconds, so a line at any wait short enough to help would land on most searches and bring back the chatter the reaction replaces. To show a long wait, pass `onProgress` and show its stage, such as `checking_out`, as a status line or a typing indicator.\n\nWith `onItem` on `buy.turn`, the 👀 still goes to `onReaction` and never joins the turn's items, because it sits on the shopper's bubble rather than in the agent's sequence. Without an `onReaction`, the text instant reply is the turn's first `text` item, as before.\n\nWhen the 👀 went out, the model reads `shopper_already_told_looking: true` in that turn's answers, and the tool's description tells it not to acknowledge the request again, so its reply opens with the answer or the question rather than `on it`. It reads false on a turn that reacted with nothing, and when `onReaction` threw. An `onReaction` that throws costs only the reaction.\n\n### Acknowledge in text, or not at all\n\nFor SMS, or any chat that shows no reactions, acknowledge in text. Pass `onWorking` and no `onReaction`, or set `ack: 'text'`, and the shopper reads an instant reply instead, such as `on it, looking for usb-c cables under $20` or `give me a sec, checking for a table for 2 in north beach`:\n\n```ts\nconst buy = buyTool({\n  agentcard,\n  externalUserId: shopper.id,\n  ack: 'text',\n  onWorking: (text) => textShopper(shopper.id, text),\n});\n```\n\n`ack` takes `'reaction'`, `'text'` or `'none'`. Left out, the tool reacts when the tool or the turn has an `onReaction`, and sends text through `onWorking` otherwise, so an app built on 0.9 with only `onWorking` keeps its text replies. With both callbacks, the shopper gets the 👀 and never the text too. `'none'`, or `false`, sends nothing.\n\nIn text mode, a streamed search's reply is Agentcard's own line, written from the conversation while it searches, such as `one sec, checking target for la croix`, and it reaches `onWorking` before the cards or not at all. A search `buy.turn` sends straight that has shown the shopper nothing by twice `ackDelayMs`, because Agentcard wrote no line or its line was dropped, sends `one moment` once, and a line of Agentcard's that comes after it is dropped. When your model's run fails before it wrote or called anything, call `turn.end()` before you show your error, so no wait line follows it. When `turn.stopped` is true after a call, the shopper sent a new message while this turn ran and Agentcard stopped the turn for it: end the turn there, with no model call, no error and no saved history, because the new message's turn answers. With `stream: false`, the tool sends its own reply when Agentcard has not answered a new request within `ackDelayMs`, 1 second by default, so a quick answer arrives alone. It sends one for the calls the model makes in one turn, where a call that starts within 15 seconds of the last one ending counts as the same turn. A slow confirm or pick never hears `looking for`: a pick, of a product, a store or a place in a list such as `the first one`, hears `got it, one moment`, a confirm hears `on it, one moment`, and any other answer hears `one moment`. A turn opened with `buy.turn` that has shown the shopper nothing, no line and no card, after the delay sends that line once. None of them names anything the shopper said, and a code hears nothing. The words rotate through six templates, and one tool never sends the same template twice in a row. A short paraphrase of the request goes in when the tool can read one: it stops before any link, email address, phone number, street address or long number, and a request that starts with one gets a reply that names nothing, such as `looking for that now`. The call waits for `onWorking`, so the shopper reads the reply before any link and before the model answers. An `onWorking` that throws costs only the instant reply.\n\nPass `ack: (ask) => text` to write your own text from the shopper's words, where an empty answer sends none, and `ackDelayMs` to change the 1 second for either mode.\n\nThe model takes several seconds to call the tool after the shopper's message arrives. Without `buy.turn`, react sooner by calling `buy.instantReaction(message)` the moment the message arrives, before your model runs, and put the emoji it returns on the message. In text mode, call `buy.instantAck(message)` and send the text it returns:\n\n```ts\nconst reaction = buy.instantReaction(message); // '👀' or null\nif (reaction) await reactToShopperMessage(shopper.id, reaction);\n// In text mode instead:\nconst ack = buy.instantAck(message);\nif (ack) await textShopper(shopper.id, ack);\n```\n\nWith `buy.turn`, pass `onReaction` or `onWorking` to the turn instead: it acknowledges the moment the turn opens, and calls `instantReaction` or `instantAck` for you. When either returns a 👀 or a reply, the tool sends none of its own for that turn.\n\n`instantReaction` and `instantAck` return null for a message that starts no search: a confirmation or a short answer such as `yes`, `1` or `ok`, a step toward paying for the cart such as `ok lets checkout`, `place the order` or `pay`, an acknowledgement such as `its ok`, `thats fine` or `sounds good`, a pick of a product the shopper already saw, such as `the first one`, `#2`, `I want the blue one` or a card's title with its price, a pick of a store, such as `order here` or a store card's `Order from Tacos El Grullense`, a code, small talk such as `hi` or `how are you`, a message that carries the shopper's own details, such as a name with a phone number, an email address, a street address, a bare house number and street such as `1801 wedemeyer`, or a zip code, any message that answers the last answer's request for an address, shipping or guest details or a code, and a short reply right after any other question the last answer asked, such as `im a 37` after `what size do you want?`, or `carne asada` after `which meat?`. A reply that opens a new request, such as `find me black running shoes`, or that runs past four words is still a search. The reply never reads those details back, never repeats the shopper's own first-person words, and names the request only when it reads as a short, whole phrase; otherwise it says `on it, give me a moment` or another reply that names nothing. The tool also reads a message that quotes the name of a product its last answer showed, or names one of the stores its last answer listed and nothing else to buy, as a pick of it. A request for a store the shopper did not see, such as `order from chipotle`, reads back as `looking for chipotle`, never `looking for from chipotle`. When it returns a reply, the tool sends none of its own through `onWorking` for that turn, and the model reads `shopper_already_told_looking: true`, so the shopper hears one acknowledgement. When it returns null for a message that picks nothing, such as `yes`, a call that runs past `ackDelayMs` still acknowledges: with a 👀 in reaction mode, and in text mode with an `onWorking` reply that names nothing and never says it is looking for anything, such as `one moment`, and when it returns null for a pick, such a call sends `got it, one moment`.\n\nWithout a buy tool, `instantReaction(message, { nextAction, asked, stores })` and `instantAck(message, { previous, nextAction, asked, stores })` from the package root decide the same way, and `ACK_REACTION` is the `👀` `instantReaction` returns: `previous` is the reply you sent last, so the next one comes from another template, `nextAction` is the last answer's `next_action`, `asked` is the last message the shopper read, so an answer to its question for an address, a name or a code, or a short answer to any other question it asked, gets none, and `stores` holds the names of the stores the last answer listed, so a message that picks one gets none. Pass `ack: 'none'` to the tool when you acknowledge yourself. `ackFor` is the earlier name of the same function.\n\n## Show what Agentcard is doing\n\nThe tool streams every call, so each part of an answer reaches your app the moment Agentcard produces it: the stage the call reached, the products a search found, each message Agentcard writes and the cart it builds. Pass a callback for each part you show:\n\n```ts\nconst buy = buyTool({\n  agentcard,\n  externalUserId: shopper.id,\n  sendLink: (link) => textShopper(shopper.id, link.url),\n  onStatus: ({ text }) => showStatus(shopper.id, text),\n  onFound: ({ shown, found, more }) => showCount(shopper.id, `${shown} of ${found} shown`, more),\n  onProducts: (products, { merchantName }) => showProducts(shopper.id, merchantName, products),\n  onText: (text) => textShopper(shopper.id, text),\n  onCart: (cart, { carts }) => showCart(shopper.id, cart, carts),\n});\n```\n\n- `onStatus` hears each step the moment Agentcard starts it, as a line to show in place of loading dots: `searching Target and Walmart`, `adding it to your cart`, `working through the store's checkout`. `step` names the step, such as `searching` or `adding_to_cart`, for an app that writes its own words. A call that only writes its reply sends none, so keep your dots until the first line comes.\n- `onFound` hears how many products the searches found, after the cards it counts: `shown` cards of `found` products, such as \"8 of 23 shown\", each time the count grows. `more` holds the products past the cards as product links, in the order they were found, for a \"show more\" that runs no new search. The model never reads them.\n- `onProgress` still hears the stage, `searching`, `building_cart`, `checking_out` or `working`.\n- `onAvailability` hears whether the places a booking's cards show have room at the time the shopper asked for. A place's card can go out before Agentcard's live search knows: its `availability` reads `checking`, so show it without its choose button. The update names each card by its `productId` with `available` (its open times in `slots`, empty when none were named), `unavailable` (full then) or `unknown` (the search could not say). Change the card in place, and offer it as a choice only when it reads `available`. A call that ends with a card still `checking` sends `unknown` for it. Every other card, a retail product's included, carries no `availability`.\n- `onProducts` hears the products a search found the moment it answers, before Agentcard writes its reply, with the conversation, when the search ran (`asOf`) and the store's name. With `sendLink`, each product's card goes out then too, a few seconds before the answer, and the answer sends only the cards it adds. Pass `earlyCards: false` to send only the cards the answer names, with the answer: the reply often names only some of a search's products.\n- `onText` hears each message Agentcard writes, links included, the moment it is written, and after the cards of the search it is about.\n- `onCart` hears the cart a confirm would place, or null, and every cart on the table, each time a call builds or changes one, before the message that announces it.\n\n`buy.turn` takes the same callbacks, and each one left out falls back to the tool's. A turn's `onText` hears each message in its place in the turn, after the instant reply and the cards, paced by `pace`, and `turn.items` lists it; `onItem` does not hear it, so an app that passes both hears each message once.\n\nWhen your app shows Agentcard's messages through `onText`, the model reads `shopper_already_read_reply: true` in that call's answer and adds nothing to them, as it reads `shopper_already_told_looking` after an instant reply: end the turn without a second model call, as with `replyAsWritten`, or let the model add one short line for what the reply left out. `turn.replyAsWritten` stays null for that answer, so the reply never reaches the shopper twice, and a step link the turn holds for your model's next message goes out right after Agentcard's ask instead.\n\nA turn built with `replyAsWritten` and `earlyCards` that hears messages through `onMessage` or `onItem` and passes no `onText` gets the same once a reply is written while a slower source's cards are still coming, such as a second hotel supplier's: Agentcard's messages go out through that callback the moment Agentcard says the reply is written, the slower cards and their one message follow in the same call, and the answer reads `shopper_already_read_reply: true`. `turn.replyAsWritten` then holds the messages the shopper read, and `turn.say` of it sends nothing, so an app that shows the reply as written and skips its model shows no second reply.\n\nA stream that breaks after the call started reads the conversation for what the turn left, as a turn past Agentcard's budget does. Pass `stream: false` to wait for each whole answer, with its cards sent beside it.\n\nCode that calls the client itself streams with `agentcard.buy(body, handlers)`: `onCatalog`, `onSegment`, `onCart` and `onDelta` hear their events in the order Agentcard sent them, each once the one before it settled, and the answer waits for the last of them. `onDelta` asks Agentcard for the pieces of each message as it writes them, a draft that each `onSegment` message replaces.\n\n## Send each paragraph as its own message\n\nA chat ","readmeFilename":"README.md"}