Apps

Fastify SDK

The @payweave/fastify package plugs into Fastify's preHandler hook. The recommended entry point is payweave.route(), which bundles validation, charging, auto-refund, and marketplace registration.

Installation

Terminal
npm install @payweave/fastify zod

Full example

TypeScript
import Fastify from 'fastify';
import { Payweave } from '@payweave/fastify';
import { z } from 'zod';

const app = Fastify();

const payweave = new Payweave(
  process.env.PAYWEAVE_APP_ID!,
  process.env.PAYWEAVE_APP_SECRET!
);

payweave.assertConfigured(); // fail early on missing env

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);

await app.listen({ port: 3000 });

Dynamic pricing

TypeScript
payweave.route(app, 'post', '/api/summarize', {
  price: async (req) => {
    const body = req.body as { text: string };
    return body.text.length > 5000 ? '0.01' : '0.002';
  },
  inputSchema: z.object({ text: z.string() }),
  handler: async (_req, body) => summarize(body.text),
});

Accessing payment metadata

TypeScript
handler: async (req, body) => {
  const txHash = (req as any).payweaveTransactionHash;
  const payer = (req as any).payweavePayer;
  const receipt = (req as any).payweaveReceipt;
  return { txHash, payer };
}

Manual refund

TypeScript
payweave.route(app, 'post', '/api/weather', {
  price: '0.001',
  refundOnError: false,
  inputSchema: WeatherInput,
  handler: async (req, body, reply) => {
    try {
      return await fetchWeather(body.city);
    } catch (err: any) {
      if (err.status === 429) {
        await payweave.refund({
          transactionHash: (req as any).payweaveTransactionHash!,
          reason: 'upstream_rate_limited',
        });
        reply.status(429).send({ error: 'rate_limited', retry_after: 60 });
        return;
      }
      throw err;
    }
  },
});

Low-level: payweave.charge()

TypeScript
app.get(
  '/api/custom',
  { preHandler: payweave.charge({ price: '0.001', description: 'Custom' }) },
  async (_req, reply) => reply.send({ ok: true })
);
Fastify parses JSON bodies automatically, so no extra middleware is needed. Just declare your routes with payweave.route() and call mountSync(app) once.