Merchant SDK

Accept USDC payments from AI agents with Express or Hono middleware.

The @pincerpay/merchant package provides middleware for Express and Hono that handles the full x402 payment flow — returning 402 challenges, verifying payment proofs, and confirming settlement.

Installation

npm install @pincerpay/merchant

Express

import express from "express";
import { pincerpay } from "@pincerpay/merchant";

const app = express();

app.use(
  pincerpay({
    apiKey: process.env.PINCERPAY_API_KEY!,
    merchantAddress: "YOUR_SOLANA_WALLET_ADDRESS",
    routes: {
      "GET /api/weather": {
        price: "0.01",
        chain: "solana",
        description: "Current weather data",
      },
      "GET /api/forecast": {
        price: "0.05",
        chain: "solana",
        description: "7-day forecast",
      },
    },
  })
);

app.get("/api/weather", (req, res) => {
  res.json({ temp: 72, condition: "sunny" });
});

app.listen(3000);

Hono

import { Hono } from "hono";
import { pincerpayHono } from "@pincerpay/merchant";

const app = new Hono();

app.use(
  "*",
  pincerpayHono({
    apiKey: process.env.PINCERPAY_API_KEY!,
    merchantAddress: "YOUR_SOLANA_WALLET_ADDRESS",
    routes: {
      "GET /api/weather": {
        price: "0.01",
        chain: "solana",
        description: "Current weather data",
      },
    },
  })
);

app.get("/api/weather", (c) => {
  return c.json({ temp: 72, condition: "sunny" });
});

export default app;

Configuration

The pincerpay() / pincerpayHono() functions accept a PincerPayConfig object:

Option Type Required Description
apiKey string Yes Your PincerPay API key (pp_live_...)
merchantAddress string Yes Your wallet address for receiving USDC
facilitatorUrl string No Override facilitator URL (default: https://facilitator.pincerpay.com)
routes Record<string, RoutePaywallConfig> Yes Map of endpoint patterns to paywall config

Route Configuration

Each route in routes accepts:

Option Type Required Description
price string Yes Price in USDC (e.g. "0.01")
chain string No Chain shorthand (default: "solana")
chains string[] No Multiple chains the agent can pay on
description string No Description shown to agents in 402 response

Supported Chains

Shorthand Network Use
solana Solana Mainnet Production
solana-devnet Solana Devnet Testing
base Base Mainnet Production (EVM)
base-sepolia Base Sepolia Testing (EVM)
polygon Polygon Mainnet Production (EVM)
polygon-amoy Polygon Amoy Testing (EVM)

Environment Variables

Variable Required Description
PINCERPAY_API_KEY Yes Your API key from the dashboard

Webhook Verification

When you configure a webhook URL in the dashboard, PincerPay signs every webhook delivery with your webhook secret using HMAC-SHA256. Verify the signature to ensure requests are authentic.

import crypto from "node:crypto";
import express from "express";

const WEBHOOK_SECRET = process.env.PINCERPAY_WEBHOOK_SECRET!;

app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.headers["x-pincerpay-signature"] as string;
  if (!signature) return res.status(401).send("Missing signature");

  const parts = Object.fromEntries(
    signature.split(",").map((p) => p.split("=") as [string, string])
  );

  const signedContent = `${parts.t}.${req.body.toString()}`;
  const expected = crypto
    .createHmac("sha256", WEBHOOK_SECRET)
    .update(signedContent)
    .digest("hex");

  if (!crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected))) {
    return res.status(401).send("Invalid signature");
  }

  // Signature valid - process the event
  const event = JSON.parse(req.body.toString());
  console.log(event.event, event.transaction.txHash);
  res.sendStatus(200);
});

Your webhook secret is available in the dashboard settings. See the Testing guide for more verification examples.

Helpers

toBaseUnits()

Convert human-readable USDC to base units (6 decimals):

import { toBaseUnits } from "@pincerpay/merchant";

toBaseUnits("0.01");  // "10000"
toBaseUnits("1.00");  // "1000000"
toBaseUnits("10.00"); // "10000000"

USDC Amount Reference

Human-Readable Base Units
$0.01 "10000"
$0.10 "100000"
$1.00 "1000000"
$10.00 "10000000"