What you will build

A production-ready HTTP endpoint that charges 0.01 USDC per request, runs an OpenAI call behind it, and returns the result. Callers only get billed when the AI call succeeds. The wallet receiving the USDC is an isolated MoltPe agent wallet with a spending policy, so even if your server is compromised the attacker cannot drain it beyond your configured sweep rules.

The architecture is boring in the best way. One Express app, one middleware, one LLM call, one deployment. No queues, no webhooks, no Stripe account, no KYC flow. The x402 protocol does all the payment coordination over vanilla HTTP headers.

When you are done you will have a URL like https://your-api.run.app/v1/summarize that any MoltPe-equipped agent can call and pay automatically. Callers include Claude Desktop, Cursor agents, LangChain pipelines, or other paid API agents chaining together.

Prerequisites

Step 1 — Create a receiving agent wallet

Spin up a MoltPe wallet that will collect USDC from callers. This is a receive agent — it does not spend, it only accumulates. Keep the agent ID handy; you will paste the wallet address into the x402 middleware config.

# Create an isolated receiving wallet on Polygon mainnet.
curl -X POST https://api.moltpe.com/v1/agents/create \
  -H "Authorization: Bearer $MOLTPE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "summarizer-api-receiver", "network": "polygon" }'
{
  "agent_id": "ag_01JMT3K9P4R7X2VB8N5CQZDHEW",
  "wallet_address": "0xC3e9F1d3B5a7C9e1F3b5A7c9E1f3B5a7C9e1F3b5",
  "network": "polygon",
  "status": "active"
}

Step 2 — Scaffold the Express server

Create a fresh Node project and install the three packages you need: Express for the HTTP surface, the MoltPe x402 middleware for payment gating, and the OpenAI SDK for the AI call behind the paywall.

mkdir paid-summarizer && cd paid-summarizer
npm init -y
npm install express @moltpe/x402-express openai

Create server.js with one public health route and a stubbed paid route you will fill in next.

// server.js — entry point for the paid summarization API.
import express from "express";
import OpenAI from "openai";

const app = express();
app.use(express.json());

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

app.get("/health", (req, res) => res.json({ ok: true }));

// Paid route: wired up in Step 3.
app.post("/v1/summarize", (req, res) => res.status(501).json({ todo: true }));

const port = process.env.PORT || 8080;
app.listen(port, () => console.log(`paid-summarizer on :${port}`));

Step 3 — Add the x402 middleware and AI handler

This is the whole trick. Drop moltpeX402() in front of the handler. Callers without payment get a 402 with payment instructions; callers with a valid proof fall through to your AI code. The middleware verifies every payment against MoltPe before calling next().

// Paid /v1/summarize route. Price: 0.01 USDC per request.
import { moltpeX402 } from "@moltpe/x402-express";

const requirePayment = moltpeX402({
  price: "0.01",
  token: "USDC",
  network: "polygon",
  recipient: "0xC3e9F1d3B5a7C9e1F3b5A7c9E1f3B5a7C9e1F3b5",
  apiKey: process.env.MOLTPE_API_KEY,
  idempotencyWindowSeconds: 60,
});

app.post("/v1/summarize", requirePayment, async (req, res) => {
  const { text } = req.body;
  if (!text) return res.status(400).json({ error: "text required" });

  try {
    const completion = await openai.chat.completions.create({
      model: "gpt-4o-mini",
      messages: [
        { role: "system", content: "Summarize in 2 sentences." },
        { role: "user", content: text },
      ],
    });
    res.json({ summary: completion.choices[0].message.content });
  } catch (err) {
    // Auto-refund if the AI call fails — caller shouldn't pay for errors.
    await fetch("https://api.moltpe.com/v1/payments/refund", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${process.env.MOLTPE_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ payment_id: req.moltpePaymentId, reason: "llm_failure" }),
    });
    res.status(502).json({ error: "ai_failed_refund_issued" });
  }
});

Read the error handler carefully. If the LLM call throws, the middleware has already confirmed the caller paid — so we immediately refund. This turns the endpoint into a pay-on-success service, which dramatically improves caller trust.

Step 4 — Set receive-side policy and sweep

A receiving wallet should not hoard funds. Configure MoltPe to sweep accumulated USDC to your treasury wallet once per day. This limits blast radius if the API key ever leaks — an attacker can only touch what accumulated since the last sweep.

curl -X POST https://api.moltpe.com/v1/agents/ag_01JMT3K9P4R7X2VB8N5CQZDHEW/sweep-policy \
  -H "Authorization: Bearer $MOLTPE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "treasury_address": "0xF1d3B5a7C9e1F3b5A7c9E1f3B5a7C9e1F3b5A7c9",
    "frequency": "daily",
    "min_balance_to_sweep": "10.00"
  }'

From now on, any time the balance crosses 10 USDC, MoltPe moves it to your treasury wallet automatically. You never log in to a dashboard to move funds.

Step 5 — Deploy to Cloud Run or Vercel

Both platforms work. Here is the Cloud Run path because it gives you a stable URL and full Node runtime. Create a Dockerfile, build, and deploy.

# Dockerfile — minimal Node 20 container for the paid API.
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "server.js"]
gcloud run deploy paid-summarizer \
  --source . \
  --region us-central1 \
  --allow-unauthenticated \
  --update-env-vars MOLTPE_API_KEY=$MOLTPE_API_KEY,OPENAI_API_KEY=$OPENAI_API_KEY

Cloud Run returns a URL like https://paid-summarizer-xyz.run.app. That is your paid API. Vercel works the same way with vercel --prod after setting the same env vars in the project settings.

Testing the agent

Use the MoltPe x402 client from a second terminal or a separate agent wallet. The client automatically handles the 402 handshake.

// Client agent — calls the paid endpoint, pays transparently.
import { createX402Client } from "@moltpe/x402-client";

const client = createX402Client({
  apiKey: process.env.MOLTPE_API_KEY,
  agentId: "ag_01JMT5R7W2X9B4V6N3CQZDPKEM", // a spending agent
  maxPaymentUsd: "0.05",
});

const res = await client.fetch("https://paid-summarizer-xyz.run.app/v1/summarize", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ text: "Long article to summarize..." }),
});

console.log(await res.json());
// { summary: "Two-sentence summary of the input text." }

In the MoltPe dashboard, the receiving wallet balance ticks up by 0.01 USDC per successful call. Refunded failures never show. This is your live usage graph — no Stripe webhook, no analytics pipeline needed.

Production checklist