npm package: @mixrpay/merchant-sdk
Description: Add x402 payments to your API in minutes - middleware for Express, Next.js, and Fastify
Author: MixrPay
Latest version: 0.5.2

# @mixrpay/merchant-sdk

Accept payments from AI agents and web apps. One SDK for backend middleware and frontend widget integration.

## Installation

```bash
npm install @mixrpay/merchant-sdk
```

## Exports

| Import Path | Purpose |
|-------------|---------|
| `@mixrpay/merchant-sdk` | Core utilities, webhook verification |
| `@mixrpay/merchant-sdk/express` | Express middleware |
| `@mixrpay/merchant-sdk/nextjs` | Next.js App Router wrapper |
| `@mixrpay/merchant-sdk/fastify` | Fastify plugin |
| `@mixrpay/merchant-sdk/widget` | Programmatic widget injection |
| `@mixrpay/merchant-sdk/widget-elements` | TypeScript types for widget elements |

## Environment Variables

```bash
MIXRPAY_PUBLIC_KEY=pk_live_...
MIXRPAY_SECRET_KEY=sk_live_...
MIXRPAY_WEBHOOK_SECRET=whsec_...
MIXRPAY_HMAC_SECRET=hmac_...
```

Get credentials from [Developer Settings](https://www.mixrpay.com/seller/developers).

---

## Backend Middleware

Wrap your API routes to require payment. Works with sessions from the Widget or Agent SDK.

### Express

```typescript
import express from 'express';
import { mixrpay } from '@mixrpay/merchant-sdk/express';

const app = express();
app.use(express.json());

app.post('/api/generate', mixrpay({ priceUsd: 0.05 }), (req, res) => {
  const { payer, amountUsd, method } = req.mixrPayment!;
  res.json({ result: 'success' });
});
```

### Next.js (App Router)

```typescript
import { withMixrPay, MixrPayPaymentResult } from '@mixrpay/merchant-sdk/nextjs';
import { NextRequest, NextResponse } from 'next/server';

async function handler(req: NextRequest, payment: MixrPayPaymentResult) {
  return NextResponse.json({ result: 'success', payer: payment.payer });
}

export const POST = withMixrPay({ priceUsd: 0.05 }, handler);
```

### Fastify

```typescript
import Fastify from 'fastify';
import { x402Plugin, x402 } from '@mixrpay/merchant-sdk/fastify';

const app = Fastify();
app.register(x402Plugin);

app.post('/api/generate', { preHandler: x402({ price: 0.05 }) }, async (req) => {
  return { result: 'success' };
});
```

### Middleware Options

```typescript
mixrpay({
  priceUsd: 0.05,                    // Fixed price
  getPrice: (req) => calculatePrice(req.body),  // Dynamic pricing
  feature: 'ai-chat',                // Feature slug for tracking
  onPayment: (payment) => log(payment),  // Callback on success
  skip: (req) => req.user?.isPremium,    // Skip payment conditionally
})
```

---

## Frontend Widget

### HTML (Simple)

```html
<script 
  src="https://www.mixrpay.com/widget.js"
  data-seller-public-key="pk_live_..."
  data-user-token="{{ serverGeneratedToken }}">
</script>

<mixr-balance></mixr-balance>

<button data-meter-feature="generate" data-meter-price-usd="0.05">
  Generate ($0.05)
</button>
```

### Programmatic (SPA/React/Vue)

```typescript
import { injectWidget, isWidgetLoaded } from '@mixrpay/merchant-sdk/widget';

// Inject widget with config
await injectWidget({
  publicKey: 'pk_live_...',
  userToken: serverGeneratedToken,
  theme: 'dark',
});

// Use the widget API
if (isWidgetLoaded()) {
  window.Mixr.openWallet();
  window.Mixr.charge('feature', '0.05', buttonElement);
}
```

### Widget Events

```typescript
window.addEventListener('mixr:charge-success', (e) => {
  const { feature, price, txHash } = e.detail;
  // Payment succeeded, unlock feature
});

window.addEventListener('mixr:low-balance', (e) => {
  // User needs to add funds
});

window.addEventListener('mixr:session-updated', (e) => {
  const { sessionId, remainingUsd } = e.detail;
  // Session state changed
});
```

### TypeScript Support

```typescript
// For custom element types in JSX
import '@mixrpay/merchant-sdk/widget-elements';

// Now TypeScript knows about:
<mixr-balance data-theme="dark" />
<mixr-wallet />
```

---

## Platform Configuration (MerchantClient)

Programmatically configure LLM models, MCP tools, markup, and features without the dashboard.

```typescript
import { MerchantClient } from '@mixrpay/merchant-sdk';

const client = new MerchantClient({
  secretKey: process.env.MIXRPAY_SECRET_KEY!,
});

// Set 15% markup on platform features (min 10%)
await client.setMarkup({ percent: 15 });

// Enable LLM models
const { models } = await client.listLLMModels();
await client.enableLLMModel('gpt-4o-mini');
await client.enableLLMModel('claude-3-5-haiku-latest');

// Enable gateway tools
const { tools } = await client.listGatewayTools();
await client.enableGatewayTool('exa-search');
await client.enableGatewayTool('tavily-search');

// Create your own features
await client.createFeature({
  slug: 'premium-search',
  displayName: 'Premium Search',
  priceUsd: 0.10,
});

// Sync multiple features at once
await client.syncFeatures({
  features: [
    { slug: 'search', displayName: 'Search', priceUsd: 0.05 },
    { slug: 'analyze', displayName: 'Analyze', priceUsd: 0.10 },
  ],
});
```

### MerchantClient Methods

| Method | Description |
|--------|-------------|
| `getMarkup()` | Get current markup settings |
| `setMarkup({ percent })` | Set markup percentage (10-200%) |
| `listLLMModels()` | List all LLM models with enablement status |
| `enableLLMModel(modelId)` | Enable an LLM model |
| `disableLLMModel(modelId)` | Disable an LLM model |
| `listGatewayTools()` | List all gateway tools with enablement status |
| `enableGatewayTool(toolSlug)` | Enable a gateway tool |
| `disableGatewayTool(toolSlug)` | Disable a gateway tool |
| `listFeatures()` | List your features |
| `createFeature(params)` | Create a new feature |
| `syncFeatures(params)` | Bulk upsert features |

### Error Handling

```typescript
import { MerchantClient, MerchantAPIError } from '@mixrpay/merchant-sdk';

try {
  await client.enableLLMModel('gpt-4o-mini');
} catch (error) {
  if (error instanceof MerchantAPIError) {
    console.error(`API Error: ${error.message} (${error.status})`);
    if (error.retryAfterSeconds) {
      console.log(`Retry after ${error.retryAfterSeconds} seconds`);
    }
  }
}
```

---

## Webhooks

```typescript
import { verifySessionWebhook } from '@mixrpay/merchant-sdk';

app.post('/webhooks/mixrpay', (req, res) => {
  const sig = req.headers['x-mixrpay-signature'] as string;
  
  if (!verifySessionWebhook(JSON.stringify(req.body), sig, process.env.MIXRPAY_WEBHOOK_SECRET!)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  const { event, amount_usd, user_wallet } = req.body;
  // Handle: session.created, session.charged, session.revoked, session.expired
  
  res.json({ received: true });
});
```

---

## Documentation

- [Integration Guide](https://www.mixrpay.com/seller/integrate)
- [API Reference](https://www.mixrpay.com/seller/api-reference)
- [Widget Docs](https://www.mixrpay.com/seller/widget)

## License

MIT