@mixrpay/merchant-sdk 0.3.3 → 0.3.5

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 CHANGED
@@ -1,33 +1,28 @@
1
1
  # @mixrpay/merchant-sdk
2
2
 
3
- Accept payments from AI agents and web apps with one middleware. Supports session-based payments (Agent SDK, Widget) and x402 protocol.
3
+ Accept payments from AI agents and web apps with one middleware.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
8
  npm install @mixrpay/merchant-sdk
9
- # or
10
- yarn add @mixrpay/merchant-sdk
11
- # or
12
- pnpm add @mixrpay/merchant-sdk
13
9
  ```
14
10
 
15
- ## Quick Start
16
-
17
- ### 1. Set Environment Variables
11
+ ## Setup
18
12
 
19
13
  ```bash
20
14
  # .env
21
- MIXRPAY_PUBLIC_KEY=pk_live_... # Your merchant public key
22
- MIXRPAY_SECRET_KEY=sk_live_... # Your merchant secret key
23
-
24
- # Optional: for x402 protocol support
25
- MIXRPAY_MERCHANT_ADDRESS=0xYourWalletAddress
15
+ MIXRPAY_PUBLIC_KEY=pk_live_...
16
+ MIXRPAY_SECRET_KEY=sk_live_...
17
+ MIXRPAY_WEBHOOK_SECRET=whsec_...
18
+ MIXRPAY_HMAC_SECRET=hmac_... # For Widget user linking
26
19
  ```
27
20
 
28
- ### 2. Add to Your Routes
21
+ Get credentials from [Developer Settings](https://www.mixrpay.com/seller/developers).
29
22
 
30
- #### Express
23
+ ## API Middleware
24
+
25
+ ### Express
31
26
 
32
27
  ```typescript
33
28
  import express from 'express';
@@ -35,431 +30,102 @@ import { mixrpay } from '@mixrpay/merchant-sdk/express';
35
30
 
36
31
  const app = express();
37
32
 
38
- // Accepts payments from Widget, Agent SDK, and x402 agents
39
33
  app.post('/api/generate', mixrpay({ priceUsd: 0.05 }), (req, res) => {
40
- // Payment verified! Access via req.mixrPayment
41
- const { payer, amountUsd, method } = req.mixrPayment!;
42
-
43
- console.log(`Payment: $${amountUsd} via ${method} from ${payer}`);
44
-
45
- const result = processRequest(req.body);
46
- res.json(result);
34
+ const { payer, amountUsd } = req.mixrPayment!;
35
+ res.json({ result: 'success' });
47
36
  });
48
-
49
- // Dynamic pricing based on request
50
- app.post('/api/ai', mixrpay({
51
- getPrice: (req) => req.body?.premium ? 0.10 : 0.05
52
- }), handler);
53
37
  ```
54
38
 
55
- #### Next.js (App Router)
39
+ ### Next.js
56
40
 
57
41
  ```typescript
58
- // app/api/generate/route.ts
59
- import { withMixrPay, MixrPayment } from '@mixrpay/merchant-sdk/nextjs';
42
+ import { withMixrPay } from '@mixrpay/merchant-sdk/nextjs';
60
43
  import { NextRequest, NextResponse } from 'next/server';
61
44
 
62
- async function handler(req: NextRequest, payment: MixrPayment) {
63
- // payment contains: { payer, amountUsd, method, sessionId?, chargeId?, txHash? }
64
- console.log(`Paid by ${payment.payer}: $${payment.amountUsd} via ${payment.method}`);
65
-
45
+ async function handler(req: NextRequest, payment) {
66
46
  return NextResponse.json({ result: 'success' });
67
47
  }
68
48
 
69
49
  export const POST = withMixrPay({ priceUsd: 0.05 }, handler);
70
50
  ```
71
51
 
72
- #### Fastify
52
+ ### Fastify
73
53
 
74
54
  ```typescript
75
55
  import Fastify from 'fastify';
76
56
  import { mixrpayPlugin, mixrpay } from '@mixrpay/merchant-sdk/fastify';
77
57
 
78
58
  const app = Fastify();
59
+ app.register(mixrpayPlugin);
79
60
 
80
- // Register plugin with defaults
81
- app.register(mixrpayPlugin, {
82
- publicKey: process.env.MIXRPAY_PUBLIC_KEY,
83
- secretKey: process.env.MIXRPAY_SECRET_KEY,
84
- });
85
-
86
- // Use on routes
87
61
  app.post('/api/generate', {
88
62
  preHandler: mixrpay({ priceUsd: 0.05 })
89
- }, async (req, reply) => {
90
- return { result: 'success', payer: req.mixrPayment?.payer };
91
- });
92
- ```
93
-
94
- ## Accepted Payment Methods
95
-
96
- The middleware automatically handles **three payment methods**:
97
-
98
- | Header | Source | Description |
99
- |--------|--------|-------------|
100
- | `X-Mixr-Session` | Agent SDK | Session-based payment (recommended for MixrPay clients) |
101
- | `X-Mixr-Payment` | Widget | Widget payment proof JWT |
102
- | `X-PAYMENT` | x402 | External agent payment via x402 protocol |
103
-
104
- ```typescript
105
- app.post('/api/generate', mixrpay({ priceUsd: 0.05 }), (req, res) => {
106
- const { method } = req.mixrPayment!;
107
-
108
- switch (method) {
109
- case 'session':
110
- console.log('Payment from Agent SDK');
111
- break;
112
- case 'widget':
113
- console.log('Payment from Widget user');
114
- break;
115
- case 'x402':
116
- console.log('Payment from external x402 agent');
117
- break;
118
- }
119
-
120
- res.json({ result: 'success' });
121
- });
122
- ```
123
-
124
- ## How It Works
125
-
126
- ### Session-Based Flow (Agent SDK / Widget)
127
-
128
- ```
129
- Agent/User Your API MixrPay
130
- │ │ │
131
- │ 1. Request with │ │
132
- │ X-Mixr-Session header │ │
133
- ├───────────────────────────▶│ │
134
- │ │ 2. Validate session │
135
- │ ├──────────────────────────▶│
136
- │ │◀──────────────────────────┤
137
- │ 3. Response │ │
138
- │◀───────────────────────────┤ │
139
- ```
140
-
141
- ### x402 Flow (External Agents)
142
-
143
- ```
144
- Agent Your API Facilitator
145
- │ │ │
146
- │ 1. Request (no payment) │ │
147
- ├───────────────────────────▶│ │
148
- │◀── 402 Payment Required ───┤ │
149
- │ │ │
150
- │ 2. Request with │ │
151
- │ X-PAYMENT header │ │
152
- ├───────────────────────────▶│ │
153
- │ │ 3. Verify & settle │
154
- │ ├──────────────────────────▶│
155
- │ │◀──────────────────────────┤
156
- │ 4. Response │ │
157
- │◀───────────────────────────┤ │
158
- ```
159
-
160
- ## Configuration Options
161
-
162
- ### MixrPayOptions
163
-
164
- ```typescript
165
- interface MixrPayOptions {
166
- /** Price in USD (e.g., 0.05 for 5 cents) */
167
- priceUsd?: number;
168
-
169
- /** Dynamic pricing function */
170
- getPrice?: (req: Request) => number | Promise<number>;
171
-
172
- /** Your public key (defaults to MIXRPAY_PUBLIC_KEY env var) */
173
- publicKey?: string;
174
-
175
- /** Your secret key (defaults to MIXRPAY_SECRET_KEY env var) */
176
- secretKey?: string;
177
-
178
- /** Wallet address for x402 (defaults to MIXRPAY_MERCHANT_ADDRESS env var) */
179
- merchantAddress?: string;
180
-
181
- /** x402 facilitator URL (default: https://x402.org/facilitator) */
182
- facilitator?: string;
183
-
184
- /** Description shown to payer */
185
- description?: string;
186
-
187
- /** Callback after successful payment */
188
- onPayment?: (payment: MixrPayment) => void | Promise<void>;
189
-
190
- /** Skip payment for certain requests */
191
- skip?: (req: Request) => boolean | Promise<boolean>;
192
-
193
- /** Test mode - accepts test payments */
194
- testMode?: boolean;
195
- }
196
- ```
197
-
198
- ### Payment Result
199
-
200
- ```typescript
201
- interface MixrPayment {
202
- /** Whether payment is valid */
203
- valid: boolean;
204
-
205
- /** Payment method used */
206
- method: 'session' | 'widget' | 'x402';
207
-
208
- /** Payer's wallet address */
209
- payer: string;
210
-
211
- /** Amount paid in USD */
212
- amountUsd: number;
213
-
214
- /** Session ID (for session-based payments) */
215
- sessionId?: string;
216
-
217
- /** Charge record ID */
218
- chargeId?: string;
219
-
220
- /** Settlement transaction hash (for x402) */
221
- txHash?: string;
222
-
223
- /** When payment was made */
224
- timestamp: Date;
225
-
226
- /** Error message if invalid */
227
- error?: string;
228
-
229
- /** Whether payment was pre-charged by the agent (session only) */
230
- preCharged?: boolean;
231
- }
232
- ```
233
-
234
- ### Pre-Charged Sessions
235
-
236
- When AI agents use the Agent SDK, they can pre-charge before calling your API by passing `X-Mixr-Charged: <amount>`. The middleware detects this and validates the session without double-charging:
237
-
238
- ```typescript
239
- // Agent SDK calls your API with pre-charged session
240
- // Headers: { 'X-Mixr-Session': 'sess_abc', 'X-Mixr-Charged': '0.05' }
241
-
242
- app.post('/api/query', mixrpay({ priceUsd: 0.05 }), (req, res) => {
243
- const { preCharged, amountUsd, payer } = req.mixrPayment!;
244
-
245
- if (preCharged) {
246
- // Agent pre-charged - session validated only, no additional charge made
247
- console.log(`Pre-charged payment of $${amountUsd} from ${payer}`);
248
- } else {
249
- // Middleware charged the session
250
- console.log(`Charged $${amountUsd} from ${payer}`);
251
- }
252
-
253
- res.json({ result: 'success' });
63
+ }, async (req) => {
64
+ return { result: 'success' };
254
65
  });
255
66
  ```
256
67
 
257
- ## Advanced Usage
258
-
259
- ### Dynamic Pricing
260
-
261
- ```typescript
262
- app.post('/api/ai', mixrpay({
263
- getPrice: async (req) => {
264
- const { model, tokens } = req.body;
265
-
266
- // Price based on model and usage
267
- const rates = { 'gpt-4': 0.03, 'gpt-3.5': 0.002 };
268
- const rate = rates[model] || 0.01;
269
-
270
- return rate * (tokens / 1000);
271
- }
272
- }), handler);
273
- ```
274
-
275
- ### Skip Payment for Certain Requests
68
+ ## Widget Integration
276
69
 
277
- ```typescript
278
- app.post('/api/query', mixrpay({
279
- priceUsd: 0.05,
280
- skip: async (req) => {
281
- // Free for authenticated premium users
282
- const user = await getUser(req.headers.authorization);
283
- return user?.isPremium || false;
284
- }
285
- }), handler);
286
- ```
70
+ ```html
71
+ <script
72
+ src="https://www.mixrpay.com/widget.js"
73
+ data-seller-public-key="pk_live_..."
74
+ data-user-token="{{ signedToken }}">
75
+ </script>
287
76
 
288
- ### Payment Callbacks
77
+ <mixr-balance></mixr-balance>
289
78
 
290
- ```typescript
291
- app.post('/api/query', mixrpay({
292
- priceUsd: 0.05,
293
- onPayment: async (payment) => {
294
- // Log to your analytics
295
- await analytics.track('payment_received', {
296
- payer: payment.payer,
297
- amount: payment.amountUsd,
298
- method: payment.method,
299
- });
300
-
301
- // Store in database
302
- await db.payments.create({
303
- data: {
304
- payer: payment.payer,
305
- amount: payment.amountUsd,
306
- chargeId: payment.chargeId,
307
- }
308
- });
309
- }
310
- }), handler);
79
+ <button data-meter-feature="generate" data-meter-price-usd="0.10">
80
+ Generate ($0.10)
81
+ </button>
311
82
  ```
312
83
 
313
- ### Manual Verification
84
+ ### Generate User Tokens
314
85
 
315
86
  ```typescript
316
- import { verifyMixrPayment } from '@mixrpay/merchant-sdk';
87
+ import crypto from 'crypto';
317
88
 
318
- // Manual verification without middleware
319
- const result = await verifyMixrPayment(req.headers, {
320
- publicKey: process.env.MIXRPAY_PUBLIC_KEY,
321
- secretKey: process.env.MIXRPAY_SECRET_KEY,
322
- expectedAmount: 0.05,
323
- });
324
-
325
- if (result.valid) {
326
- console.log(`Valid payment from ${result.payer} via ${result.method}`);
89
+ function generateUserToken(userId: string): string {
90
+ const timestamp = Date.now();
91
+ const data = `${userId}:${timestamp}`;
92
+ const signature = crypto
93
+ .createHmac('sha256', process.env.MIXRPAY_HMAC_SECRET!)
94
+ .update(data)
95
+ .digest('hex');
96
+ return `${data}:${signature}`;
327
97
  }
328
98
  ```
329
99
 
330
- ### Webhook Verification
331
-
332
- Verify webhook signatures to ensure events are from MixrPay:
100
+ ## Webhooks
333
101
 
334
102
  ```typescript
335
103
  import { verifySessionWebhook } from '@mixrpay/merchant-sdk';
336
104
 
337
105
  app.post('/webhooks/mixrpay', (req, res) => {
338
- const signature = req.headers['x-mixrpay-signature'] as string;
339
- const payload = JSON.stringify(req.body);
106
+ const sig = req.headers['x-mixrpay-signature'] as string;
340
107
 
341
- // Verify signature using your webhook secret from the dashboard
342
- if (!verifySessionWebhook(payload, signature, process.env.WEBHOOK_SECRET!)) {
108
+ if (!verifySessionWebhook(JSON.stringify(req.body), sig, process.env.MIXRPAY_WEBHOOK_SECRET!)) {
343
109
  return res.status(401).json({ error: 'Invalid signature' });
344
110
  }
345
111
 
346
- const event = req.body;
347
-
348
- switch (event.event) {
349
- case 'session.created':
350
- // New session authorized
351
- console.log(`Session created: ${event.session_id} from ${event.user_wallet}`);
352
- console.log(`Spending limit: $${event.spending_limit_usd}`);
353
- break;
354
-
355
- case 'session.charged':
356
- // Successful charge against a session
357
- console.log(`Charged $${event.amount_usd} from ${event.user_wallet}`);
358
- console.log(`Remaining: $${event.remaining_usd}`);
359
- // Update your database, trigger fulfillment, etc.
360
- break;
361
-
362
- case 'session.revoked':
363
- // User revoked their session
364
- console.log(`Session revoked: ${event.session_id}`);
365
- break;
366
-
367
- case 'session.expired':
368
- // Session expired
369
- console.log(`Session expired: ${event.session_id}`);
370
- break;
371
- }
372
-
112
+ // Handle event
373
113
  res.json({ received: true });
374
114
  });
375
115
  ```
376
116
 
377
- Configure webhook URLs in your [MixrPay Dashboard](https://www.mixrpay.com/seller/developers).
378
-
379
- ## Testing
380
-
381
- Enable test mode to accept test payments during development:
382
-
383
- ```typescript
384
- app.post('/api/query', mixrpay({
385
- priceUsd: 0.05,
386
- testMode: process.env.NODE_ENV !== 'production',
387
- }), handler);
388
- ```
389
-
390
- ## Environment Variables
391
-
392
- | Variable | Description | Required |
393
- |----------|-------------|----------|
394
- | `MIXRPAY_PUBLIC_KEY` | Your merchant public key (pk_...) | Yes |
395
- | `MIXRPAY_SECRET_KEY` | Your merchant secret key | Yes |
396
- | `MIXRPAY_MERCHANT_ADDRESS` | Wallet address for x402 payments | For x402 |
397
-
398
- ## Supported Chains
399
-
400
- | Chain | Chain ID | USDC Contract |
401
- |-------|----------|---------------|
402
- | Base Mainnet | 8453 | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
403
- | Base Sepolia | 84532 | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` |
404
-
405
- ## Error Handling
406
-
407
- The middleware returns appropriate HTTP status codes:
408
-
409
- - `402 Payment Required` - No payment or invalid payment
410
- - `403 Forbidden` - Session limit exceeded or revoked
411
- - `500 Internal Server Error` - Configuration issues
412
-
413
- Error responses include details:
414
-
415
- ```json
416
- {
417
- "error": "payment_required",
418
- "message": "No valid payment provided",
419
- "paymentInfo": {
420
- "priceUsd": 0.05,
421
- "recipient": "0x...",
422
- "acceptedMethods": ["X-Mixr-Session", "X-Mixr-Payment", "X-PAYMENT"]
423
- }
424
- }
425
- ```
426
-
427
- ## TypeScript Support
428
-
429
- Full TypeScript support with type definitions included.
117
+ ## TypeScript
430
118
 
431
119
  ```typescript
432
120
  import type { MixrPayOptions, MixrPayment } from '@mixrpay/merchant-sdk';
433
- ```
434
121
 
435
- ### Widget Custom Elements (React/JSX)
436
-
437
- If you're using the MixrPay widget with TypeScript and React, import the type declarations:
438
-
439
- ```typescript
440
- // In your app's entry file or a .d.ts file
122
+ // Widget element types
441
123
  import '@mixrpay/merchant-sdk/widget-elements';
442
-
443
- // Now these work without TypeScript errors:
444
- <mixr-balance data-theme="dark" />
445
- <mixr-wallet />
446
124
  ```
447
125
 
448
- ## Migration from x402-Only
449
-
450
- If you were using the old x402-only middleware:
451
-
452
- ```typescript
453
- // Before (x402 only)
454
- import { x402 } from '@mixrpay/merchant-sdk/express';
455
- app.post('/api/query', x402({ price: 0.05 }), handler);
456
-
457
- // After (unified - backwards compatible)
458
- import { mixrpay } from '@mixrpay/merchant-sdk/express';
459
- app.post('/api/query', mixrpay({ priceUsd: 0.05 }), handler);
460
- ```
126
+ ## Documentation
461
127
 
462
- The new `mixrpay` middleware is backwards compatible—it still accepts x402 payments via `X-PAYMENT` header, but now also accepts session-based payments.
128
+ Full documentation at [mixrpay.com/seller/docs](https://www.mixrpay.com/seller/docs)
463
129
 
464
130
  ## License
465
131