@dexterai/x402 1.9.0 → 1.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -8
- package/dist/client/index.cjs +28 -0
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +2 -1
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.js +25 -0
- package/dist/client/index.js.map +1 -1
- package/dist/react/index.cjs +40 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +10 -1
- package/dist/react/index.d.ts +10 -1
- package/dist/react/index.js +38 -1
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.cjs +140 -109
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +17 -7
- package/dist/server/index.d.ts +17 -7
- package/dist/server/index.js +139 -109
- package/dist/server/index.js.map +1 -1
- package/dist/{x402-client-BDaOwfgE.d.cts → sponsored-access-BCB2CxdG.d.cts} +68 -1
- package/dist/{x402-client-DIcp-PvX.d.ts → sponsored-access-H1EX6zpi.d.ts} +68 -1
- package/package.json +7 -8
package/README.md
CHANGED
|
@@ -77,10 +77,22 @@ The simplest way to make x402 payments from scripts:
|
|
|
77
77
|
```typescript
|
|
78
78
|
import { wrapFetch } from '@dexterai/x402/client';
|
|
79
79
|
|
|
80
|
+
// Solana
|
|
80
81
|
const x402Fetch = wrapFetch(fetch, {
|
|
81
82
|
walletPrivateKey: process.env.SOLANA_PRIVATE_KEY,
|
|
82
83
|
});
|
|
83
84
|
|
|
85
|
+
// EVM (Base, Polygon, Arbitrum, Optimism, Avalanche, SKALE)
|
|
86
|
+
const x402Fetch = wrapFetch(fetch, {
|
|
87
|
+
evmPrivateKey: process.env.EVM_PRIVATE_KEY, // requires: npm install viem
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Both — SDK picks the chain with balance
|
|
91
|
+
const x402Fetch = wrapFetch(fetch, {
|
|
92
|
+
walletPrivateKey: process.env.SOLANA_PRIVATE_KEY,
|
|
93
|
+
evmPrivateKey: process.env.EVM_PRIVATE_KEY,
|
|
94
|
+
});
|
|
95
|
+
|
|
84
96
|
// That's it. 402 responses are handled automatically.
|
|
85
97
|
const response = await x402Fetch('https://api.example.com/protected');
|
|
86
98
|
```
|
|
@@ -580,20 +592,113 @@ tiktoken's default encoding works well for most transformer models. Only use a c
|
|
|
580
592
|
|
|
581
593
|
---
|
|
582
594
|
|
|
583
|
-
## Sponsored Access (
|
|
595
|
+
## Sponsored Access (Ads for Agents)
|
|
596
|
+
|
|
597
|
+
Sponsored Access delivers targeted resource recommendations through x402 payments. When an agent pays for an API, the facilitator can inject a recommendation for a related tool in the settlement receipt. The agent sees the recommendation and can call it immediately -- the subsequent call is tracked as a conversion with both blockchain transaction hashes as proof.
|
|
598
|
+
|
|
599
|
+
### Server — Enable Recommendation Injection
|
|
584
600
|
|
|
585
|
-
|
|
601
|
+
Add `sponsoredAccess: true` to your middleware config. This reads `extensions["sponsored-access"]` from the facilitator's settlement response and injects `_x402_sponsored` into the JSON response body so the agent's LLM can see the recommendations (headers are invisible to LLMs).
|
|
586
602
|
|
|
587
603
|
```typescript
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
604
|
+
import { x402Middleware } from '@dexterai/x402/server';
|
|
605
|
+
|
|
606
|
+
// Default injection: adds _x402_sponsored field to JSON response
|
|
607
|
+
app.get('/api/data',
|
|
608
|
+
x402Middleware({
|
|
609
|
+
payTo: '...', amount: '0.01',
|
|
610
|
+
sponsoredAccess: true,
|
|
611
|
+
}),
|
|
612
|
+
(req, res) => res.json({ data: 'content' })
|
|
613
|
+
);
|
|
614
|
+
// Agent receives: { _x402_sponsored: [{ resourceUrl, description, sponsor }], data: 'content' }
|
|
615
|
+
|
|
616
|
+
// Custom injection: control where recommendations appear
|
|
617
|
+
app.get('/api/data',
|
|
618
|
+
x402Middleware({
|
|
619
|
+
payTo: '...', amount: '0.01',
|
|
620
|
+
sponsoredAccess: {
|
|
621
|
+
inject: (body, recs) => ({ ...body, related_tools: recs }),
|
|
622
|
+
onMatch: (recs, settlement) => {
|
|
623
|
+
console.log(`Matched ${recs.length} recommendations for tx ${settlement.transaction}`);
|
|
624
|
+
},
|
|
625
|
+
},
|
|
626
|
+
}),
|
|
627
|
+
(req, res) => res.json({ data: 'content' })
|
|
628
|
+
);
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
### Client — Read Recommendations
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
import {
|
|
635
|
+
wrapFetch,
|
|
636
|
+
getSponsoredRecommendations,
|
|
637
|
+
fireImpressionBeacon,
|
|
638
|
+
} from '@dexterai/x402/client';
|
|
639
|
+
|
|
640
|
+
const x402Fetch = wrapFetch(fetch, { walletPrivateKey: key });
|
|
641
|
+
const response = await x402Fetch('https://api.example.com/data');
|
|
642
|
+
|
|
643
|
+
// Extract typed recommendations from the payment receipt
|
|
644
|
+
const recs = getSponsoredRecommendations(response);
|
|
645
|
+
if (recs) {
|
|
646
|
+
for (const rec of recs) {
|
|
647
|
+
console.log(`${rec.sponsor}: ${rec.description} -- ${rec.resourceUrl}`);
|
|
648
|
+
}
|
|
649
|
+
// Confirm delivery to the ad network
|
|
650
|
+
await fireImpressionBeacon(response);
|
|
651
|
+
}
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
### React — Recommendations in Hooks
|
|
655
|
+
|
|
656
|
+
```tsx
|
|
657
|
+
import { useX402Payment } from '@dexterai/x402/react';
|
|
658
|
+
|
|
659
|
+
function PayButton() {
|
|
660
|
+
const {
|
|
661
|
+
fetch,
|
|
662
|
+
isLoading,
|
|
663
|
+
sponsoredRecommendations, // auto-populated after payment
|
|
664
|
+
} = useX402Payment({ wallets });
|
|
665
|
+
|
|
666
|
+
return (
|
|
667
|
+
<div>
|
|
668
|
+
<button onClick={() => fetch(url)} disabled={isLoading}>Pay</button>
|
|
669
|
+
{sponsoredRecommendations?.map((rec, i) => (
|
|
670
|
+
<a key={i} href={rec.resourceUrl}>{rec.sponsor}: {rec.description}</a>
|
|
671
|
+
))}
|
|
672
|
+
</div>
|
|
673
|
+
);
|
|
674
|
+
}
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
### Types
|
|
678
|
+
|
|
679
|
+
All types are re-exported from `@dexterai/x402-ads-types`:
|
|
680
|
+
|
|
681
|
+
```typescript
|
|
682
|
+
import type { SponsoredRecommendation, SponsoredAccessSettlementInfo } from '@dexterai/x402/client';
|
|
683
|
+
|
|
684
|
+
interface SponsoredRecommendation {
|
|
685
|
+
resourceUrl: string; // The URL to call
|
|
686
|
+
description: string; // Agent-readable description
|
|
687
|
+
sponsor: string; // Brand name
|
|
688
|
+
bazaarId?: string; // Bazaar catalog ID
|
|
689
|
+
price?: string; // Cost in atomic units
|
|
690
|
+
currency?: string; // e.g., "USDC"
|
|
691
|
+
}
|
|
592
692
|
```
|
|
593
693
|
|
|
594
|
-
|
|
694
|
+
### How It Works
|
|
595
695
|
|
|
596
|
-
|
|
696
|
+
1. Agent pays for an API via x402
|
|
697
|
+
2. Facilitator settles payment and calls the ad network's match API
|
|
698
|
+
3. If a campaign matches (by URL pattern, category, network), a recommendation is injected into `SettlementResponse.extensions["sponsored-access"]`
|
|
699
|
+
4. Publisher middleware (with `sponsoredAccess: true`) injects it into the JSON response body
|
|
700
|
+
5. Agent's LLM sees the recommendation and can call the suggested resource
|
|
701
|
+
6. If the agent calls it, the facilitator records a conversion with both tx hashes as proof
|
|
597
702
|
|
|
598
703
|
---
|
|
599
704
|
|
package/dist/client/index.cjs
CHANGED
|
@@ -195,7 +195,10 @@ __export(client_exports, {
|
|
|
195
195
|
createKeypairWallet: () => createKeypairWallet,
|
|
196
196
|
createSolanaAdapter: () => createSolanaAdapter,
|
|
197
197
|
createX402Client: () => createX402Client,
|
|
198
|
+
fireImpressionBeacon: () => fireImpressionBeacon,
|
|
198
199
|
getPaymentReceipt: () => getPaymentReceipt,
|
|
200
|
+
getSponsoredAccessInfo: () => getSponsoredAccessInfo,
|
|
201
|
+
getSponsoredRecommendations: () => getSponsoredRecommendations,
|
|
199
202
|
isEvmKeypairWallet: () => isEvmKeypairWallet,
|
|
200
203
|
isKeypairWallet: () => isKeypairWallet,
|
|
201
204
|
wrapFetch: () => wrapFetch
|
|
@@ -1151,6 +1154,28 @@ function wrapFetch(fetchImpl, options) {
|
|
|
1151
1154
|
}
|
|
1152
1155
|
return clientFetch;
|
|
1153
1156
|
}
|
|
1157
|
+
|
|
1158
|
+
// src/client/sponsored-access.ts
|
|
1159
|
+
function getSponsoredAccessInfo(response) {
|
|
1160
|
+
const receipt = getPaymentReceipt(response);
|
|
1161
|
+
if (!receipt?.extensions?.["sponsored-access"]) return void 0;
|
|
1162
|
+
return receipt.extensions["sponsored-access"];
|
|
1163
|
+
}
|
|
1164
|
+
function getSponsoredRecommendations(response) {
|
|
1165
|
+
const info = getSponsoredAccessInfo(response);
|
|
1166
|
+
if (!info?.recommendations?.length) return void 0;
|
|
1167
|
+
return info.recommendations;
|
|
1168
|
+
}
|
|
1169
|
+
async function fireImpressionBeacon(response) {
|
|
1170
|
+
const info = getSponsoredAccessInfo(response);
|
|
1171
|
+
const beaconUrl = info?.tracking?.impressionBeacon;
|
|
1172
|
+
if (!beaconUrl) return false;
|
|
1173
|
+
try {
|
|
1174
|
+
await fetch(beaconUrl, { method: "GET" });
|
|
1175
|
+
} catch {
|
|
1176
|
+
}
|
|
1177
|
+
return true;
|
|
1178
|
+
}
|
|
1154
1179
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1155
1180
|
0 && (module.exports = {
|
|
1156
1181
|
BASE_MAINNET,
|
|
@@ -1163,7 +1188,10 @@ function wrapFetch(fetchImpl, options) {
|
|
|
1163
1188
|
createKeypairWallet,
|
|
1164
1189
|
createSolanaAdapter,
|
|
1165
1190
|
createX402Client,
|
|
1191
|
+
fireImpressionBeacon,
|
|
1166
1192
|
getPaymentReceipt,
|
|
1193
|
+
getSponsoredAccessInfo,
|
|
1194
|
+
getSponsoredRecommendations,
|
|
1167
1195
|
isEvmKeypairWallet,
|
|
1168
1196
|
isKeypairWallet,
|
|
1169
1197
|
wrapFetch
|