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 zod

Full 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.