paybondpaybond
Sign in

Next.js agent checkout

Build a Next.js App Router agent with Vercel AI SDK and Paybond — request-scoped bind, toolApproval, and guarded checkout tools.

Shopping and checkout agents in Next.js typically combine the App Router, the Vercel AI SDK, and server-side secrets. Paybond belongs on the server — bind middleware per request, never expose capability tokens to the browser.

Server-only Paybond

Run Paybond.open() and instrument() in Route Handlers or Server Actions. Pass guarded tools to generateText / streamText on the server. Client components receive streamed text — not raw capability tokens.

Try it

Terminal
Terminal commandSwipe to inspect long lines
paybond login
paybond agent demo vercel-ai smoke \
  --operation commerce.checkout \
  --requested-spend-cents 1000 \
  --evidence-preset cost_and_completion \
  --format table

Scaffold the shopping preset:

Terminal
Terminal commandSwipe to inspect long lines
paybond init --solution shopping --max-spend-usd 100 --framework vercel-ai --non-interactive
paybond policy init --preset shopping --out paybond.policy.yaml

Load policy once at module scope; resolve the active bind per request:

// lib/paybond.ts
import { Paybond } from "@paybond/kit";
import { AsyncLocalStorage } from "node:async_hooks";

const paybond = await Paybond.open({ apiKey: process.env.PAYBOND_API_KEY! });
const requestStore = new AsyncLocalStorage<{ runtime: Awaited<ReturnType<typeof instrumented.bind>> }>();

const instrumented = await paybond.instrument({
  policy: "./paybond.policy.yaml",
  framework: "vercel-ai",
  tools: {
    checkout: checkoutToolDef,
    searchProducts: searchProductsToolDef,
  },
  context: () => requestStore.getStore()!.runtime,
});

export { paybond, instrumented, requestStore };

Route handler

// app/api/agent/route.ts
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
import { instrumented, requestStore } from "@/lib/paybond";

export async function POST(req: Request) {
  const { prompt, intentId, capabilityToken } = await req.json();

  const runtime = await instrumented.bind({ intentId, capabilityToken });
  const { agentTools: tools, toolApproval } = runtime;

  return requestStore.run({ runtime }, async () => {
    const result = streamText({
      model: openai("gpt-4.1"),
      tools,
      toolApproval,
      prompt,
    });
    return result.toDataStreamResponse();
  });
}

Sandbox rehearsal: use paybond.agent({ policy: "shopping", framework: "vercel-ai", tools }) to skip manual bind during local dev.

Shopping preset defaults

ToolSide effectingCap
commerce.checkoutYes$100 per call / $100 intent budget
search.productsNo

See Let agents buy groceries for the full multi-tool shopping walkthrough.

Production checklist

  1. Create and fund intents server-side — Fund intents by rail.
  2. Pass intentId + capabilityToken from your session layer — not from unauthenticated client identifiers alone.
  3. Validate policy in CI: paybond policy validate-tools --file paybond.policy.yaml --local-only.

Developer reference: /docs/kit/vercel-ai.