Quickstart

Add AI-agent order verification to a Node.js checkout in a few minutes. It starts in shadow mode, so nothing is blocked until you decide to enforce.

You need Node.js 18.17 or newer. The verifier has no runtime dependencies.

1. Install

npm install @provethebuy/verify

The package is published with the first tagged release. Until then, install it from a clone of the repo with npm install ./packages/verify.

2. Verify a request

import { ProveTheBuy, KeyDirectory, KNOWN_DIRECTORIES } from "@provethebuy/verify";

const ptb = new ProveTheBuy({
  merchantId: "acct_your_shop",                       // as it appears in mandates and payment tokens
  keys: new KeyDirectory({ sources: [{ name: "visa", url: KNOWN_DIRECTORIES.visa }] }),
  policy: { mode: "shadow" },                         // record decisions, never block
});

const result = await ptb.verify({ method: "POST", url, headers, body });
// result.decision: "allow" | "step_up" | "block" | "not_agent"

Pass the raw body bytes exactly as received. A signature covers the bytes, so a body that was parsed and re-serialised will not verify.

3. Or use the Express middleware

import express from "express";
import { ProveTheBuy, KeyDirectory, KNOWN_DIRECTORIES, FileLedger } from "@provethebuy/verify";
import { createMiddleware } from "@provethebuy/verify/express";

const ptb = new ProveTheBuy({
  merchantId: "acct_your_shop",
  keys: new KeyDirectory({ sources: [{ name: "visa", url: KNOWN_DIRECTORIES.visa }] }),
  policy: { mode: "shadow" },
});

const agents = createMiddleware(ptb, new FileLedger("acct_your_shop", "evidence.jsonl"));
const app = express();

// capture() must come before any body parser, so the bytes are kept exactly as signed.
app.post("/checkout", agents.capture(), agents.verify(), (req, res) => {
  const paymentIntent = chargeTheCustomer(req);       // your existing payment code
  agents.record(req, { paymentIntent });              // write the evidence record
  res.json({ ok: true });
});

4. Read the decision

Every request gets req.provethebuy:

{
  decision: "allow",                // allow | step_up | block | not_agent
  reasons: ["Verified agent, valid mandate, order inside its limits."],
  enforced: false,                  // true only in enforce mode
  agent:   { keyid: "shopassist-k1", protocol: "visa-tap", tag: "agent-payer-auth" },
  mandate: { type: "verifiable-intent", mode: "autonomous", valid: true },
  checks:  [ /* every check, with pass / fail / warn / skip and a plain-English detail */ ]
}

Requests from people (no agent signature) come back as not_agent and pass straight through. When you're happy with what shadow mode shows, set mode: "enforce": step-ups return 409 and blocks return 403.

5. Running more than one server

Nonces must be remembered across servers to stop replays. Use the Redis store, or Upstash over HTTP on serverless:

import { UpstashReplayStore } from "@provethebuy/verify";

const replay = new UpstashReplayStore({
  url: process.env.UPSTASH_REDIS_REST_URL,
  token: process.env.UPSTASH_REDIS_REST_TOKEN,
});

6. Send records to ProveTheBuy Cloud (optional)

Cloud keeps records for up to 25 months and handles agent-order disputes on Stripe. The connection runs in the background and fails open.

import { connectCloud } from "@provethebuy/verify";

const cloud = connectCloud(ledger, { apiKey: process.env.PROVETHEBUY_API_KEY });
// serverless: await cloud.flush() before the response ends

Get an API key at app.provethebuy.com.

Next