@mixrpay/merchant-sdk
v0.5.2
Published
Add x402 payments to your API in minutes - middleware for Express, Next.js, and Fastify
Readme
@mixrpay/merchant-sdk
Accept payments from AI agents and web apps. One SDK for backend middleware and frontend widget integration.
Installation
npm install @mixrpay/merchant-sdkExports
| 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
MIXRPAY_PUBLIC_KEY=pk_live_...
MIXRPAY_SECRET_KEY=sk_live_...
MIXRPAY_WEBHOOK_SECRET=whsec_...
MIXRPAY_HMAC_SECRET=hmac_...Get credentials from Developer Settings.
Backend Middleware
Wrap your API routes to require payment. Works with sessions from the Widget or Agent SDK.
Express
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)
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
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
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)
<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)
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
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
// 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.
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
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
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
License
MIT
