Apps
Express SDK
The @payweave/express package adds payment gating to Express apps. The recommended entry point is payweave.route(), which bundles validation, charging, auto-refund, and marketplace registration.
Installation
Terminal
npm install @payweave/express zodFull example
TypeScript
import express from 'express';
import { Payweave } from '@payweave/express';
import { z } from 'zod';
const app = express();
app.use(express.json()); // required — payweave.route() reads req.body
const payweave = new Payweave(
process.env.PAYWEAVE_APP_ID!,
process.env.PAYWEAVE_APP_SECRET!
);
// Fail loudly if env is missing, before any request lands.
payweave.assertConfigured();
const WeatherInput = z.object({ city: z.string() });
payweave.route(app, 'post', '/api/weather', {
price: '0.001',
description: 'Current weather for a city',
inputSchema: WeatherInput,
handler: async (_req, body) => {
// body: { city: string } — typed from Zod
const res = await fetch(`https://api.weather/?q=${body.city}`);
if (!res.ok) throw new Error('weather_upstream_error');
return await res.json();
},
});
payweave.mountSync(app);
app.listen(3000);Dynamic pricing
TypeScript
payweave.route(app, 'post', '/api/summarize', {
price: (req) => req.body.text.length > 5000 ? '0.01' : '0.002',
inputSchema: z.object({ text: z.string() }),
handler: async (_req, body) => summarize(body.text),
});Accessing payment metadata
The charge middleware attaches payment data to req:
TypeScript
handler: async (req, body) => {
const txHash = req.payweaveTransactionHash;
const payer = req.payweavePayer;
const receipt = req.payweaveReceipt;
return { txHash, payer };
}Manual refund
TypeScript
payweave.route(app, 'post', '/api/weather', {
price: '0.001',
refundOnError: false,
inputSchema: WeatherInput,
handler: async (req, body, res) => {
try {
return await fetchWeather(body.city);
} catch (err: any) {
if (err.status === 429) {
await payweave.refund({
transactionHash: req.payweaveTransactionHash!,
reason: 'upstream_rate_limited',
});
res.status(429).json({ error: 'rate_limited', retry_after: 60 });
return;
}
throw err;
}
},
});Low-level: payweave.charge()
TypeScript
app.get(
'/api/custom',
payweave.charge({ price: '0.001', description: 'Custom' }),
(req, res) => res.json({ ok: true })
);Make sure
express.json() runs before your routes — payweave.route() relies on req.body being parsed.