@mixrpay/agent-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,508 @@
1
+ # MixrPay Agent SDK for JavaScript/TypeScript
2
+
3
+ Enable AI agents to make autonomous payments using x402 protocol with session keys.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@mixrpay/agent-sdk)](https://www.npmjs.com/package/@mixrpay/agent-sdk)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue)](https://www.typescriptlang.org/)
7
+
8
+ ## πŸš€ Quick Start
9
+
10
+ ```typescript
11
+ import { AgentWallet } from '@mixrpay/agent-sdk';
12
+
13
+ // 1. Initialize with a session key (get this from the wallet owner)
14
+ const wallet = new AgentWallet({
15
+ sessionKey: 'sk_live_...'
16
+ });
17
+
18
+ // 2. Make requests - payments are handled automatically!
19
+ const response = await wallet.fetch('https://api.paid-service.com/query', {
20
+ method: 'POST',
21
+ headers: { 'Content-Type': 'application/json' },
22
+ body: JSON.stringify({ prompt: 'Hello world' })
23
+ });
24
+
25
+ // 3. Use the response just like regular fetch
26
+ console.log(await response.json());
27
+ ```
28
+
29
+ ## πŸ“¦ Installation
30
+
31
+ ```bash
32
+ npm install @mixrpay/agent-sdk
33
+ # or
34
+ yarn add @mixrpay/agent-sdk
35
+ # or
36
+ pnpm add @mixrpay/agent-sdk
37
+ ```
38
+
39
+ ## πŸ”§ Configuration
40
+
41
+ By default, the SDK connects to `http://localhost:3000`. For production, set your MixrPay server URL:
42
+
43
+ ```typescript
44
+ const wallet = new AgentWallet({
45
+ sessionKey: 'sk_live_...',
46
+ baseUrl: 'https://your-mixrpay-server.com', // Your MixrPay deployment
47
+ });
48
+
49
+ // Or use environment variable: MIXRPAY_BASE_URL
50
+ ```
51
+
52
+ ## βœ… Verify Installation
53
+
54
+ Run this quick test to ensure the SDK is installed correctly:
55
+
56
+ ```typescript
57
+ import { AgentWallet, SDK_VERSION } from '@mixrpay/agent-sdk';
58
+
59
+ // Check SDK version
60
+ console.log(`MixrPay Agent SDK v${SDK_VERSION}`);
61
+
62
+ // Create a wallet instance (will validate session key format)
63
+ try {
64
+ const wallet = new AgentWallet({
65
+ sessionKey: 'sk_test_0000000000000000000000000000000000000000000000000000000000000000',
66
+ baseUrl: 'http://localhost:3000',
67
+ });
68
+ console.log('βœ“ SDK initialized successfully');
69
+
70
+ // Check connection (will fail without a running server, but validates setup)
71
+ wallet.getBalance().catch(() => {
72
+ console.log('βœ“ SDK configured (server not running - expected in test)');
73
+ });
74
+ } catch (error) {
75
+ console.error('βœ— SDK initialization failed:', error);
76
+ }
77
+ ```
78
+
79
+ ## πŸ”‘ Getting Session Keys
80
+
81
+ Session keys are created by wallet owners and grant spending permissions to agents:
82
+
83
+ 1. **From a wallet owner**: They create a session key at your MixrPay server's `/wallet/sessions` page
84
+ 2. **Programmatically**: Via the MixrPay API (for applications managing their own wallets)
85
+
86
+ Session keys look like: `sk_live_abc123...` (mainnet) or `sk_test_abc123...` (testnet)
87
+
88
+ ### Session Key Limits
89
+
90
+ Each session key has configurable spending limits:
91
+ - **Per-transaction**: Maximum amount per single request
92
+ - **Daily**: Maximum total per 24 hours
93
+ - **Total**: Maximum lifetime spend
94
+ - **Expiration**: When the key becomes invalid
95
+
96
+ ## πŸ’‘ How It Works
97
+
98
+ ```
99
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
100
+ β”‚ Agent │────▢│ Paid API │────▢│ Facilitator β”‚
101
+ β”‚ (you) │◀────│ (402) │◀────│ (x402) β”‚
102
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
103
+ β”‚ β”‚ β”‚
104
+ β”‚ 1. Request β”‚ β”‚
105
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Άβ”‚ β”‚
106
+ β”‚ β”‚ β”‚
107
+ β”‚ 2. 402 + price β”‚ β”‚
108
+ │◀─────────────────── β”‚
109
+ β”‚ β”‚ β”‚
110
+ β”‚ 3. Sign payment β”‚ β”‚
111
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Άβ”‚ β”‚
112
+ β”‚ β”‚ 4. Process β”‚
113
+ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Άβ”‚
114
+ β”‚ β”‚ β”‚
115
+ β”‚ 5. Response β”‚ 5. Confirm β”‚
116
+ │◀───────────────────◀───────────────────
117
+ β”‚ β”‚ β”‚
118
+ ```
119
+
120
+ 1. Your agent makes a request to a paid API
121
+ 2. The server returns `402 Payment Required` with pricing
122
+ 3. The SDK automatically signs a USDC transfer authorization
123
+ 4. The facilitator processes the payment
124
+ 5. You receive the API response
125
+
126
+ ## πŸ“– Usage Examples
127
+
128
+ ### Basic Request
129
+
130
+ ```typescript
131
+ import { AgentWallet } from '@mixrpay/agent-sdk';
132
+
133
+ const wallet = new AgentWallet({
134
+ sessionKey: process.env.MIXRPAY_SESSION_KEY!,
135
+ });
136
+
137
+ // GET request
138
+ const response = await wallet.fetch('https://api.example.com/data');
139
+
140
+ // POST request with JSON
141
+ const result = await wallet.fetch('https://api.example.com/generate', {
142
+ method: 'POST',
143
+ headers: { 'Content-Type': 'application/json' },
144
+ body: JSON.stringify({ prompt: 'Write a poem' })
145
+ });
146
+ ```
147
+
148
+ ### With Payment Tracking
149
+
150
+ ```typescript
151
+ import { AgentWallet, PaymentEvent } from '@mixrpay/agent-sdk';
152
+
153
+ const wallet = new AgentWallet({
154
+ sessionKey: 'sk_live_...',
155
+ onPayment: (payment: PaymentEvent) => {
156
+ console.log(`πŸ’Έ Paid $${payment.amountUsd.toFixed(4)} to ${payment.recipient}`);
157
+ console.log(` For: ${payment.description || 'API call'}`);
158
+ },
159
+ });
160
+
161
+ // Make requests
162
+ for (let i = 0; i < 5; i++) {
163
+ await wallet.fetch(`https://api.example.com/query/${i}`);
164
+ }
165
+
166
+ // Check spending
167
+ const stats = await wallet.getSpendingStats();
168
+ console.log(`\nπŸ“Š Session Summary:`);
169
+ console.log(` Total spent: $${stats.totalSpentUsd.toFixed(2)}`);
170
+ console.log(` Transactions: ${stats.txCount}`);
171
+ console.log(` Remaining daily: $${stats.remainingDailyUsd?.toFixed(2) ?? 'unlimited'}`);
172
+ ```
173
+
174
+ ### Error Handling
175
+
176
+ ```typescript
177
+ import {
178
+ AgentWallet,
179
+ InsufficientBalanceError,
180
+ SpendingLimitExceededError,
181
+ SessionKeyExpiredError,
182
+ } from '@mixrpay/agent-sdk';
183
+
184
+ const wallet = new AgentWallet({ sessionKey: 'sk_live_...' });
185
+
186
+ try {
187
+ const response = await wallet.fetch('https://api.example.com/expensive');
188
+ console.log(await response.json());
189
+ } catch (error) {
190
+ if (error instanceof InsufficientBalanceError) {
191
+ console.log(`❌ Not enough funds: need $${error.required}, have $${error.available}`);
192
+ console.log(` Top up at: ${error.topUpUrl}`);
193
+ } else if (error instanceof SpendingLimitExceededError) {
194
+ console.log(`❌ Limit exceeded: ${error.limitType} limit is $${error.limit}`);
195
+ if (error.limitType === 'daily') {
196
+ console.log(' Try again tomorrow, or request a higher limit.');
197
+ }
198
+ } else if (error instanceof SessionKeyExpiredError) {
199
+ console.log(`❌ Session key expired at ${error.expiredAt}`);
200
+ console.log(' Request a new key from the wallet owner.');
201
+ } else {
202
+ throw error;
203
+ }
204
+ }
205
+ ```
206
+
207
+ ### With Client-Side Safety Limit
208
+
209
+ ```typescript
210
+ const wallet = new AgentWallet({
211
+ sessionKey: 'sk_live_...',
212
+ maxPaymentUsd: 1.0, // Never pay more than $1 per request
213
+ });
214
+
215
+ // If an API tries to charge more than $1, the SDK will throw
216
+ // SpendingLimitExceededError with limitType: 'client_max'
217
+ ```
218
+
219
+ ### Debug Mode
220
+
221
+ ```typescript
222
+ // Enable logging during initialization
223
+ const wallet = new AgentWallet({
224
+ sessionKey: 'sk_live_...',
225
+ logLevel: 'debug', // 'debug' | 'info' | 'warn' | 'error' | 'none'
226
+ });
227
+
228
+ // Or toggle at runtime
229
+ wallet.setDebug(true);
230
+ await wallet.fetch('https://api.example.com/endpoint');
231
+ wallet.setDebug(false);
232
+ ```
233
+
234
+ ### Diagnostics
235
+
236
+ ```typescript
237
+ const wallet = new AgentWallet({ sessionKey: 'sk_live_...' });
238
+
239
+ // Run health checks
240
+ const diagnostics = await wallet.runDiagnostics();
241
+
242
+ if (diagnostics.healthy) {
243
+ console.log('βœ… Wallet is ready to use');
244
+ console.log(` Network: ${diagnostics.network}`);
245
+ console.log(` Wallet: ${diagnostics.walletAddress}`);
246
+ } else {
247
+ console.log('❌ Issues found:');
248
+ for (const issue of diagnostics.issues) {
249
+ console.log(` - ${issue}`);
250
+ }
251
+ }
252
+ ```
253
+
254
+ ## πŸ€– AI Framework Integrations
255
+
256
+ ### Vercel AI SDK
257
+
258
+ ```typescript
259
+ import { AgentWallet, InsufficientBalanceError, SpendingLimitExceededError } from '@mixrpay/agent-sdk';
260
+ import { generateText } from 'ai';
261
+ import { openai } from '@ai-sdk/openai';
262
+ import { z } from 'zod';
263
+
264
+ const wallet = new AgentWallet({
265
+ sessionKey: process.env.MIXRPAY_SESSION_KEY!,
266
+ maxPaymentUsd: 1.00, // Safety limit per request
267
+ onPayment: (p) => console.log(`Paid $${p.amountUsd} for API call`),
268
+ });
269
+
270
+ const result = await generateText({
271
+ model: openai('gpt-4'),
272
+ tools: {
273
+ paidSearch: {
274
+ description: 'Search using a premium paid API',
275
+ parameters: z.object({ query: z.string() }),
276
+ execute: async ({ query }) => {
277
+ try {
278
+ const response = await wallet.fetch('https://api.search.com/query', {
279
+ method: 'POST',
280
+ headers: { 'Content-Type': 'application/json' },
281
+ body: JSON.stringify({ query })
282
+ });
283
+ return response.json();
284
+ } catch (error) {
285
+ if (error instanceof InsufficientBalanceError) {
286
+ return { error: 'Insufficient funds', topUpUrl: error.topUpUrl };
287
+ }
288
+ if (error instanceof SpendingLimitExceededError) {
289
+ return { error: 'Spending limit reached', limit: error.limitType };
290
+ }
291
+ throw error; // Re-throw unexpected errors
292
+ }
293
+ }
294
+ }
295
+ },
296
+ prompt: 'Search for the latest AI news and summarize it'
297
+ });
298
+ ```
299
+
300
+ ### LangChain.js
301
+
302
+ ```typescript
303
+ import { AgentWallet, InsufficientBalanceError } from '@mixrpay/agent-sdk';
304
+ import { DynamicTool } from '@langchain/core/tools';
305
+
306
+ const wallet = new AgentWallet({
307
+ sessionKey: process.env.MIXRPAY_SESSION_KEY!,
308
+ maxPaymentUsd: 0.50, // Cap per tool invocation
309
+ });
310
+
311
+ const paidSearchTool = new DynamicTool({
312
+ name: 'paid_search',
313
+ description: 'Premium search API ($0.05/query) - use for high-quality results',
314
+ func: async (query: string) => {
315
+ try {
316
+ const response = await wallet.fetch('https://api.search.com/query', {
317
+ method: 'POST',
318
+ headers: { 'Content-Type': 'application/json' },
319
+ body: JSON.stringify({ query })
320
+ });
321
+ const data = await response.json();
322
+ return JSON.stringify(data.results);
323
+ } catch (error) {
324
+ if (error instanceof InsufficientBalanceError) {
325
+ return `Error: Low balance ($${error.available}). Need $${error.required}. Top up: ${error.topUpUrl}`;
326
+ }
327
+ return `Error: ${error instanceof Error ? error.message : 'Unknown error'}`;
328
+ }
329
+ }
330
+ });
331
+
332
+ // Check spending before expensive operations
333
+ const stats = await wallet.getSpendingStats();
334
+ console.log(`Budget remaining: $${stats.remainingDailyUsd ?? 'unlimited'}`);
335
+ ```
336
+
337
+ ## πŸ“š API Reference
338
+
339
+ ### AgentWallet
340
+
341
+ ```typescript
342
+ new AgentWallet({
343
+ // Required
344
+ sessionKey: string; // Session key (sk_live_... or sk_test_...)
345
+
346
+ // Optional
347
+ walletAddress?: string; // Smart wallet address (auto-detected)
348
+ maxPaymentUsd?: number; // Client-side payment limit
349
+ onPayment?: (PaymentEvent) => void; // Payment callback
350
+ facilitatorUrl?: string; // x402 facilitator URL
351
+ baseUrl?: string; // MixrPay API base URL
352
+ timeout?: number; // Request timeout in ms (default: 30000)
353
+ logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'none';
354
+ })
355
+ ```
356
+
357
+ #### Methods
358
+
359
+ | Method | Description |
360
+ |--------|-------------|
361
+ | `fetch(url, init?)` | Make HTTP request (drop-in for native fetch) |
362
+ | `getBalance()` | Get USDC balance in USD |
363
+ | `getSpendingStats()` | Get spending statistics |
364
+ | `getSessionKeyInfo()` | Get session key details and limits |
365
+ | `getPaymentHistory()` | Get list of payments made |
366
+ | `getTotalSpent()` | Get total amount spent |
367
+ | `getWalletAddress()` | Get wallet address |
368
+ | `getNetwork()` | Get network info (Base or Base Sepolia) |
369
+ | `isTestnet()` | Check if using testnet |
370
+ | `runDiagnostics()` | Run health checks |
371
+ | `setDebug(enable)` | Toggle debug logging |
372
+ | `setLogLevel(level)` | Set log level |
373
+
374
+ ### Types
375
+
376
+ ```typescript
377
+ interface PaymentEvent {
378
+ amountUsd: number; // Payment amount in USD
379
+ recipient: string; // Recipient address
380
+ txHash: string | null; // Transaction hash
381
+ timestamp: Date; // When payment was made
382
+ description?: string; // What was paid for
383
+ url?: string; // URL that triggered payment
384
+ }
385
+
386
+ interface SpendingStats {
387
+ totalSpentUsd: number;
388
+ txCount: number;
389
+ remainingDailyUsd: number | null;
390
+ remainingTotalUsd: number | null;
391
+ expiresAt: Date | null;
392
+ }
393
+
394
+ interface SessionKeyInfo {
395
+ address: string;
396
+ isValid: boolean;
397
+ limits: {
398
+ perTxUsd: number | null;
399
+ dailyUsd: number | null;
400
+ totalUsd: number | null;
401
+ };
402
+ usage: {
403
+ todayUsd: number;
404
+ totalUsd: number;
405
+ txCount: number;
406
+ };
407
+ expiresAt: Date | null;
408
+ createdAt: Date | null;
409
+ name?: string;
410
+ }
411
+ ```
412
+
413
+ ### Exceptions
414
+
415
+ | Exception | When Thrown |
416
+ |-----------|-------------|
417
+ | `InsufficientBalanceError` | Wallet doesn't have enough USDC |
418
+ | `SessionKeyExpiredError` | Session key has expired |
419
+ | `SpendingLimitExceededError` | Payment would exceed limits |
420
+ | `PaymentFailedError` | Payment transaction failed |
421
+ | `InvalidSessionKeyError` | Invalid session key format |
422
+ | `X402ProtocolError` | Protocol handling error |
423
+
424
+ ## 🌐 Networks
425
+
426
+ | Network | Chain ID | Session Key Prefix | USDC Address |
427
+ |---------|----------|-------------------|--------------|
428
+ | Base Mainnet | 8453 | `sk_live_` | Production USDC |
429
+ | Base Sepolia | 84532 | `sk_test_` | Test USDC |
430
+
431
+ ### Testing on Testnet
432
+
433
+ 1. **Get test ETH**: Use the [Base Sepolia faucet](https://www.alchemy.com/faucets/base-sepolia)
434
+ 2. **Get test USDC**: Available from the wallet dashboard after funding with test ETH
435
+ 3. **Create test session key**: Use the wallet dashboard to create `sk_test_...` keys
436
+ 4. **Test your integration**: Use test keys with your development environment
437
+
438
+ ```typescript
439
+ // Test environment setup
440
+ const wallet = new AgentWallet({
441
+ sessionKey: process.env.MIXRPAY_SESSION_KEY!, // sk_test_...
442
+ baseUrl: 'http://localhost:3000', // Your local MixrPay server
443
+ });
444
+
445
+ // The SDK automatically detects testnet from sk_test_ prefix
446
+ ```
447
+
448
+ ## πŸ”§ Environment Variables
449
+
450
+ | Variable | Required | Description |
451
+ |----------|----------|-------------|
452
+ | `MIXRPAY_SESSION_KEY` | Yes | Your session key (`sk_live_...` or `sk_test_...`) |
453
+ | `MIXRPAY_BASE_URL` | No | MixrPay server URL (default: `http://localhost:3000`) |
454
+
455
+ ### x402 Facilitator
456
+
457
+ The SDK uses the x402 protocol facilitator at `https://x402.org/facilitator` by default. The facilitator:
458
+ - Verifies payment signatures
459
+ - Submits transactions to the blockchain
460
+ - Returns settlement confirmation
461
+
462
+ You can use a custom facilitator for testing or self-hosted deployments:
463
+ ```typescript
464
+ const wallet = new AgentWallet({
465
+ sessionKey: 'sk_live_...',
466
+ facilitatorUrl: 'https://your-facilitator.com', // Custom facilitator
467
+ });
468
+ ```
469
+
470
+ Example `.env` file:
471
+ ```bash
472
+ # Production
473
+ MIXRPAY_SESSION_KEY=sk_live_abc123...
474
+ MIXRPAY_BASE_URL=https://your-mixrpay-server.com
475
+
476
+ # Development (testnet)
477
+ MIXRPAY_SESSION_KEY=sk_test_abc123...
478
+ MIXRPAY_BASE_URL=http://localhost:3000
479
+ ```
480
+
481
+ ## πŸ”’ Security Best Practices
482
+
483
+ 1. **Store session keys securely** - Use environment variables, never commit to source
484
+ 2. **Set appropriate limits** - Use `maxPaymentUsd` as a safety net
485
+ 3. **Monitor spending** - Use `onPayment` callback and `getSpendingStats()`
486
+ 4. **Use testnet first** - Test with `sk_test_` keys before production
487
+ 5. **Configure base URL** - Always set `baseUrl` explicitly in production
488
+
489
+ ## 🌐 Browser Support
490
+
491
+ This SDK works in both Node.js and browser environments. In browsers, it uses the native `fetch` and `crypto` APIs.
492
+
493
+ ## πŸ“‹ Changelog
494
+
495
+ ### v0.1.0 (Current)
496
+ - Initial release
497
+ - Core `AgentWallet` class with x402 payment handling
498
+ - Automatic 402 response detection and payment flow
499
+ - Session key validation and spending limit enforcement
500
+ - Payment callbacks and spending statistics
501
+ - Vercel AI SDK and LangChain.js integration examples
502
+ - Debug mode and diagnostics
503
+
504
+ See [CHANGELOG.md](./CHANGELOG.md) for full release history.
505
+
506
+ ## πŸ“ License
507
+
508
+ MIT