Skip to content
Tollgate Docs

@tollgatepay/next

Wraps a Next.js App Router Route Handler (or anyfetch-style handler) behind the 402 → sign → 200 flow. Web-standard Request/Response, so it works on Node, Edge, and Vercel.

Entry points

  • initTollgate(config) — most ergonomic. Returns { wrap, instance }. Use wrap() to gate a handler.
  • createTollgate(config) — returns anTollgateInstance. Use withTollgate(instance, options, handler) for lifecycle control.
  • withTollgateNext(instance, options, handler) — typed alias for NextRequest / NextResponse consumers.

Quick example

// app/tollgate.ts — instantiated once at module scope.
import { initTollgate } from "@tollgatepay/next";

export const { wrap } = initTollgate({
  apiKey: process.env.TOLLGATE_API_KEY!,
  payoutAddress: process.env.TOLLGATE_PAYOUT_ADDRESS as `0x${string}`,
  developerSalt: process.env.TOLLGATE_DEV_SALT as `0x${string}`,
});

// app/api/premium/route.ts — gate a route behind a $0.05 charge.
import { wrap } from "../../tollgate";

export const GET = wrap({ price: 50_000 }, async (_req, payment) => {
  return Response.json({
    agent: payment.agentAddress,
    owedMicros: payment.totalOwedMicros,
  });
});

Options

The options object for wrap() (full type at packages/next/src/types.ts):

interface WithTollgateOptions {
  /** Price in micro-USDC (integer, > 0). 50_000 = $0.05. */
  price: number;
  /**
   * Force strict verification (Postgres-authoritative). Default inferred from
   * price: strict above the beta threshold ($0.10) / GA threshold ($1.00).
   */
  strict?: boolean;
  /**
   * Template override for dynamic routes. If the runtime path does not match
   * the canonicalized IOU path, the middleware normally returns
   * PATH_APPEARS_DYNAMIC. Supply e.g. "/api/users/[id]" to tell the
   * canonicalizer this path has a dynamic segment.
   */
  endpointTemplate?: string;
  /**
   * Per-agent unsettled cap in micro-USDC. When set, stricter than the
   * facilitator's global cap; still bounded by it.
   */
  maxUnsettledPerAgent?: number;
  /**
   * Behaviour when the facilitator is unreachable. Default "reject" (returns
   * 503 FACILITATOR_UNAVAILABLE). "serve-untracked" returns 200 but the IOU
   * is not recorded — trades auditability for availability.
   */
  onFacilitatorError?: "reject" | "serve-untracked";
}

Payment context

Your handler receives (req, payment). The payment object carries the verified state:

interface PaymentContext {
  agentAddress: Address;
  developerAddress: Address;
  /** Price of this specific request (micros). */
  amountMicros: number;
  /** Cumulative on this (agent, dev, path) after accepting (micros). */
  totalOwedMicros: number;
  /** Delta of this request vs the previous cumulative. */
  deltaMicros: number;
  /** Strictly monotonic nonce for the tuple. */
  nonce: bigint;
  /** Canonicalized path used for the tab key. */
  canonicalPath: string;
  /** The signature recovered and bound to agentAddress. */
  iouSignature: `0x${string}`;
  /** W3C Trace Context id shared with the middleware's spans. */
  traceId: string;
  /** True when the facilitator was consulted authoritatively. */
  strictMode: boolean;
}

Test mode

Any apiKey starting with aw_test_ puts the middleware into test mode. Requests short-circuit to deterministic scenarios picked by the x-tollgate-test-scenario header (success, signature-mismatch, deadline-expired, nonce-reused, ...). No facilitator or on-chain contact.

See also