@mixrpay/merchant-sdk 0.1.1 → 0.3.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @mixrpay/merchant-sdk
2
2
 
3
- Add x402 payments to your API in minutes. Let AI agents pay for your services automatically with USDC - no signups, no API keys, no invoices.
3
+ Accept payments from AI agents and web apps with one middleware. Supports session-based payments (Agent SDK, Widget) and x402 protocol.
4
4
 
5
5
  ## Installation
6
6
 
@@ -14,10 +14,14 @@ pnpm add @mixrpay/merchant-sdk
14
14
 
15
15
  ## Quick Start
16
16
 
17
- ### 1. Set Your Wallet Address
17
+ ### 1. Set Environment Variables
18
18
 
19
19
  ```bash
20
- # In your .env file
20
+ # .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
21
25
  MIXRPAY_MERCHANT_ADDRESS=0xYourWalletAddress
22
26
  ```
23
27
 
@@ -27,118 +31,166 @@ MIXRPAY_MERCHANT_ADDRESS=0xYourWalletAddress
27
31
 
28
32
  ```typescript
29
33
  import express from 'express';
30
- import { x402 } from '@mixrpay/merchant-sdk/express';
34
+ import { mixrpay } from '@mixrpay/merchant-sdk/express';
31
35
 
32
36
  const app = express();
33
37
 
34
- // Fixed price - $0.05 per request
35
- app.post('/api/query', x402({ price: 0.05 }), (req, res) => {
36
- // This only runs after payment is verified
37
- const { payer, amount, txHash } = req.x402Payment!;
38
+ // Accepts payments from Widget, Agent SDK, and x402 agents
39
+ app.post('/api/generate', mixrpay({ priceUsd: 0.05 }), (req, res) => {
40
+ // Payment verified! Access via req.mixrPayment
41
+ const { payer, amountUsd, method } = req.mixrPayment!;
38
42
 
39
- console.log(`Payment received: $${amount} from ${payer}`);
43
+ console.log(`Payment: $${amountUsd} via ${method} from ${payer}`);
40
44
 
41
- const result = processQuery(req.body);
45
+ const result = processRequest(req.body);
42
46
  res.json(result);
43
47
  });
44
48
 
45
49
  // Dynamic pricing based on request
46
- app.post('/api/generate', x402({
47
- getPrice: (ctx) => ctx.body?.premium ? 0.10 : 0.05
50
+ app.post('/api/ai', mixrpay({
51
+ getPrice: (req) => req.body?.premium ? 0.10 : 0.05
48
52
  }), handler);
49
53
  ```
50
54
 
51
55
  #### Next.js (App Router)
52
56
 
53
57
  ```typescript
54
- // app/api/query/route.ts
55
- import { withX402 } from '@mixrpay/merchant-sdk/nextjs';
58
+ // app/api/generate/route.ts
59
+ import { withMixrPay, MixrPayment } from '@mixrpay/merchant-sdk/nextjs';
56
60
  import { NextRequest, NextResponse } from 'next/server';
57
61
 
58
- async function handler(req: NextRequest, payment: X402PaymentResult) {
59
- // payment contains: { payer, amount, txHash, settledAt }
60
- console.log(`Paid by ${payment.payer}: $${payment.amount}`);
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}`);
61
65
 
62
66
  return NextResponse.json({ result: 'success' });
63
67
  }
64
68
 
65
- export const POST = withX402({ price: 0.05 }, handler);
69
+ export const POST = withMixrPay({ priceUsd: 0.05 }, handler);
66
70
  ```
67
71
 
68
72
  #### Fastify
69
73
 
70
74
  ```typescript
71
75
  import Fastify from 'fastify';
72
- import { x402Plugin, x402 } from '@mixrpay/merchant-sdk/fastify';
76
+ import { mixrpayPlugin, mixrpay } from '@mixrpay/merchant-sdk/fastify';
73
77
 
74
78
  const app = Fastify();
75
79
 
76
80
  // Register plugin with defaults
77
- app.register(x402Plugin, {
78
- recipient: process.env.MIXRPAY_MERCHANT_ADDRESS,
81
+ app.register(mixrpayPlugin, {
82
+ publicKey: process.env.MIXRPAY_PUBLIC_KEY,
83
+ secretKey: process.env.MIXRPAY_SECRET_KEY,
79
84
  });
80
85
 
81
86
  // Use on routes
82
- app.post('/api/query', {
83
- preHandler: x402({ price: 0.05 })
87
+ app.post('/api/generate', {
88
+ preHandler: mixrpay({ priceUsd: 0.05 })
84
89
  }, async (req, reply) => {
85
- return { result: 'success', payer: req.x402Payment?.payer };
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' });
86
121
  });
87
122
  ```
88
123
 
89
124
  ## How It Works
90
125
 
91
- 1. **Client makes request** without payment header
92
- 2. **Server returns 402** with payment requirements (amount, recipient, etc.)
93
- 3. **Client signs USDC transfer** using their session key
94
- 4. **Client retries** with `X-PAYMENT` header containing signed authorization
95
- 5. **Server verifies signature** and submits to facilitator for settlement
96
- 6. **Server processes request** after payment confirmation
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)
97
142
 
98
143
  ```
99
- Client Server Facilitator
100
- | | |
101
- |-- POST /api/query ------------>| |
102
- |<-- 402 Payment Required -------| |
103
- | | |
104
- |-- POST /api/query ------------>| |
105
- | X-PAYMENT: <signed auth> | |
106
- | |-- verify & settle ---------->|
107
- | |<-- tx hash -----------------|
108
- |<-- 200 OK --------------------| |
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
+ │◀───────────────────────────┤ │
109
158
  ```
110
159
 
111
160
  ## Configuration Options
112
161
 
113
- ### X402Options
162
+ ### MixrPayOptions
114
163
 
115
164
  ```typescript
116
- interface X402Options {
165
+ interface MixrPayOptions {
117
166
  /** Price in USD (e.g., 0.05 for 5 cents) */
118
- price: number;
167
+ priceUsd?: number;
168
+
169
+ /** Dynamic pricing function */
170
+ getPrice?: (req: Request) => number | Promise<number>;
119
171
 
120
- /** Your wallet address (defaults to MIXRPAY_MERCHANT_ADDRESS env var) */
121
- recipient?: string;
172
+ /** Your public key (defaults to MIXRPAY_PUBLIC_KEY env var) */
173
+ publicKey?: string;
122
174
 
123
- /** Chain ID (default: 8453 for Base) */
124
- chainId?: number;
175
+ /** Your secret key (defaults to MIXRPAY_SECRET_KEY env var) */
176
+ secretKey?: string;
125
177
 
126
- /** Facilitator URL (default: https://x402.org/facilitator) */
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) */
127
182
  facilitator?: string;
128
183
 
129
184
  /** Description shown to payer */
130
185
  description?: string;
131
186
 
132
- /** Dynamic pricing function */
133
- getPrice?: (context: PriceContext) => number | Promise<number>;
134
-
135
187
  /** Callback after successful payment */
136
- onPayment?: (payment: X402PaymentResult) => void | Promise<void>;
188
+ onPayment?: (payment: MixrPayment) => void | Promise<void>;
137
189
 
138
190
  /** Skip payment for certain requests */
139
- skip?: (context: SkipContext) => boolean | Promise<boolean>;
191
+ skip?: (req: Request) => boolean | Promise<boolean>;
140
192
 
141
- /** Test mode - skips on-chain settlement */
193
+ /** Test mode - accepts test payments */
142
194
  testMode?: boolean;
143
195
  }
144
196
  ```
@@ -146,21 +198,30 @@ interface X402Options {
146
198
  ### Payment Result
147
199
 
148
200
  ```typescript
149
- interface X402PaymentResult {
201
+ interface MixrPayment {
150
202
  /** Whether payment is valid */
151
203
  valid: boolean;
152
204
 
205
+ /** Payment method used */
206
+ method: 'session' | 'widget' | 'x402';
207
+
153
208
  /** Payer's wallet address */
154
- payer?: string;
209
+ payer: string;
155
210
 
156
211
  /** Amount paid in USD */
157
- amount?: number;
212
+ amountUsd: number;
213
+
214
+ /** Session ID (for session-based payments) */
215
+ sessionId?: string;
158
216
 
159
- /** Settlement transaction hash */
217
+ /** Charge record ID */
218
+ chargeId?: string;
219
+
220
+ /** Settlement transaction hash (for x402) */
160
221
  txHash?: string;
161
222
 
162
- /** When payment was settled */
163
- settledAt?: Date;
223
+ /** When payment was made */
224
+ timestamp: Date;
164
225
 
165
226
  /** Error message if invalid */
166
227
  error?: string;
@@ -172,9 +233,9 @@ interface X402PaymentResult {
172
233
  ### Dynamic Pricing
173
234
 
174
235
  ```typescript
175
- app.post('/api/ai', x402({
176
- getPrice: async (ctx) => {
177
- const { model, tokens } = ctx.body;
236
+ app.post('/api/ai', mixrpay({
237
+ getPrice: async (req) => {
238
+ const { model, tokens } = req.body;
178
239
 
179
240
  // Price based on model and usage
180
241
  const rates = { 'gpt-4': 0.03, 'gpt-3.5': 0.002 };
@@ -188,11 +249,12 @@ app.post('/api/ai', x402({
188
249
  ### Skip Payment for Certain Requests
189
250
 
190
251
  ```typescript
191
- app.post('/api/query', x402({
192
- price: 0.05,
193
- skip: (ctx) => {
252
+ app.post('/api/query', mixrpay({
253
+ priceUsd: 0.05,
254
+ skip: async (req) => {
194
255
  // Free for authenticated premium users
195
- return ctx.headers['x-premium-token'] === 'valid';
256
+ const user = await getUser(req.headers.authorization);
257
+ return user?.isPremium || false;
196
258
  }
197
259
  }), handler);
198
260
  ```
@@ -200,52 +262,52 @@ app.post('/api/query', x402({
200
262
  ### Payment Callbacks
201
263
 
202
264
  ```typescript
203
- app.post('/api/query', x402({
204
- price: 0.05,
265
+ app.post('/api/query', mixrpay({
266
+ priceUsd: 0.05,
205
267
  onPayment: async (payment) => {
206
268
  // Log to your analytics
207
269
  await analytics.track('payment_received', {
208
270
  payer: payment.payer,
209
- amount: payment.amount,
210
- txHash: payment.txHash,
271
+ amount: payment.amountUsd,
272
+ method: payment.method,
211
273
  });
212
274
 
213
275
  // Store in database
214
276
  await db.payments.create({
215
277
  data: {
216
278
  payer: payment.payer,
217
- amount: payment.amount,
218
- txHash: payment.txHash,
279
+ amount: payment.amountUsd,
280
+ chargeId: payment.chargeId,
219
281
  }
220
282
  });
221
283
  }
222
284
  }), handler);
223
285
  ```
224
286
 
225
- ### Custom Verification
287
+ ### Manual Verification
226
288
 
227
289
  ```typescript
228
- import { verifyX402Payment, usdToMinor } from '@mixrpay/merchant-sdk';
290
+ import { verifyMixrPayment } from '@mixrpay/merchant-sdk';
229
291
 
230
292
  // Manual verification without middleware
231
- const result = await verifyX402Payment(paymentHeader, {
232
- expectedAmount: usdToMinor(0.05),
233
- expectedRecipient: '0x...',
234
- chainId: 8453,
293
+ const result = await verifyMixrPayment(req.headers, {
294
+ publicKey: process.env.MIXRPAY_PUBLIC_KEY,
295
+ secretKey: process.env.MIXRPAY_SECRET_KEY,
296
+ expectedAmount: 0.05,
235
297
  });
236
298
 
237
299
  if (result.valid) {
238
- console.log(`Valid payment from ${result.payer}`);
300
+ console.log(`Valid payment from ${result.payer} via ${result.method}`);
239
301
  }
240
302
  ```
241
303
 
242
304
  ## Testing
243
305
 
244
- Enable test mode to skip on-chain settlement during development:
306
+ Enable test mode to accept test payments during development:
245
307
 
246
308
  ```typescript
247
- app.post('/api/query', x402({
248
- price: 0.05,
309
+ app.post('/api/query', mixrpay({
310
+ priceUsd: 0.05,
249
311
  testMode: process.env.NODE_ENV !== 'production',
250
312
  }), handler);
251
313
  ```
@@ -254,7 +316,9 @@ app.post('/api/query', x402({
254
316
 
255
317
  | Variable | Description | Required |
256
318
  |----------|-------------|----------|
257
- | `MIXRPAY_MERCHANT_ADDRESS` | Your wallet address to receive payments | Yes (or pass `recipient` option) |
319
+ | `MIXRPAY_PUBLIC_KEY` | Your merchant public key (pk_...) | Yes |
320
+ | `MIXRPAY_SECRET_KEY` | Your merchant secret key | Yes |
321
+ | `MIXRPAY_MERCHANT_ADDRESS` | Wallet address for x402 payments | For x402 |
258
322
 
259
323
  ## Supported Chains
260
324
 
@@ -268,14 +332,20 @@ app.post('/api/query', x402({
268
332
  The middleware returns appropriate HTTP status codes:
269
333
 
270
334
  - `402 Payment Required` - No payment or invalid payment
335
+ - `403 Forbidden` - Session limit exceeded or revoked
271
336
  - `500 Internal Server Error` - Configuration issues
272
337
 
273
338
  Error responses include details:
274
339
 
275
340
  ```json
276
341
  {
277
- "error": "Invalid payment",
278
- "reason": "Insufficient payment: expected 50000, got 10000"
342
+ "error": "payment_required",
343
+ "message": "No valid payment provided",
344
+ "paymentInfo": {
345
+ "priceUsd": 0.05,
346
+ "recipient": "0x...",
347
+ "acceptedMethods": ["X-Mixr-Session", "X-Mixr-Payment", "X-PAYMENT"]
348
+ }
279
349
  }
280
350
  ```
281
351
 
@@ -284,10 +354,38 @@ Error responses include details:
284
354
  Full TypeScript support with type definitions included.
285
355
 
286
356
  ```typescript
287
- import type { X402Options, X402PaymentResult } from '@mixrpay/merchant-sdk';
357
+ import type { MixrPayOptions, MixrPayment } from '@mixrpay/merchant-sdk';
358
+ ```
359
+
360
+ ### Widget Custom Elements (React/JSX)
361
+
362
+ If you're using the MixrPay widget with TypeScript and React, import the type declarations:
363
+
364
+ ```typescript
365
+ // In your app's entry file or a .d.ts file
366
+ import '@mixrpay/merchant-sdk/widget-elements';
367
+
368
+ // Now these work without TypeScript errors:
369
+ <mixr-balance data-theme="dark" />
370
+ <mixr-wallet />
371
+ ```
372
+
373
+ ## Migration from x402-Only
374
+
375
+ If you were using the old x402-only middleware:
376
+
377
+ ```typescript
378
+ // Before (x402 only)
379
+ import { x402 } from '@mixrpay/merchant-sdk/express';
380
+ app.post('/api/query', x402({ price: 0.05 }), handler);
381
+
382
+ // After (unified - backwards compatible)
383
+ import { mixrpay } from '@mixrpay/merchant-sdk/express';
384
+ app.post('/api/query', mixrpay({ priceUsd: 0.05 }), handler);
288
385
  ```
289
386
 
387
+ The new `mixrpay` middleware is backwards compatible—it still accepts x402 payments via `X-PAYMENT` header, but now also accepts session-based payments.
388
+
290
389
  ## License
291
390
 
292
391
  MIT
293
-