> ## Documentation Index
> Fetch the complete documentation index at: https://developers.fd.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Next.js Integration

> Protect Next.js API routes with blockchain micropayments

## Overview

The **@1stdigital/prism-nextjs** package provides middleware for Next.js API routes and App Router route handlers. Supports both Pages Router and App Router architectures.

<CardGroup cols={3}>
  <Card title="App Router" icon="layer-group">
    Support for Next.js 13+ App Router
  </Card>

  <Card title="Pages Router" icon="file">
    Works with traditional API routes
  </Card>

  <Card title="Edge Runtime" icon="bolt">
    Compatible with Edge Runtime
  </Card>
</CardGroup>

***

## Installation

<Tabs>
  <Tab title="npm">
    ```bash theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
    npm install @1stdigital/prism-nextjs next
    ```
  </Tab>

  {" "}

  <Tab title="yarn">`bash yarn add @1stdigital/prism-nextjs next `</Tab>

  <Tab title="pnpm">
    ```bash theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
    pnpm add @1stdigital/prism-nextjs next
    ```
  </Tab>
</Tabs>

***

<Note>
  The canonical SDK config is `identifyToken` (`PRISM_IDENTIFY_TOKEN` env var) — formerly `apiKey` / `PRISM_API_KEY`. SDKs accept the legacy names as fallback during the migration window; new code should use the canonical names.
</Note>

## Quick Start (App Router)

```typescript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
// app/api/premium/route.ts
import { NextRequest, NextResponse } from "next/server";
import { withPrismPayment } from "@1stdigital/prism-nextjs";

async function handler(request: NextRequest) {
  // Access payer from request
  const payer = (request as any).payer;

  return NextResponse.json({
    message: "Premium content",
    payer,
  });
}

// Wrap handler with payment middleware
export const GET = withPrismPayment(handler, {
  identifyToken: process.env.PRISM_IDENTIFY_TOKEN || "dev-key-123",
  baseUrl: "https://prism-gw.fd.xyz",
  price: 0.01, // $0.01 USD
  description: "Premium API",
});
```

***

## Quick Start (Pages Router)

```typescript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
// pages/api/premium.ts
import { NextApiRequest, NextApiResponse } from "next";
import { createPrismMiddleware } from "@1stdigital/prism-nextjs";

const prismMiddleware = createPrismMiddleware({
  identifyToken: process.env.PRISM_IDENTIFY_TOKEN || "dev-key-123",
  baseUrl: "https://prism-gw.fd.xyz",
});

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  // Apply middleware
  const paymentResult = await prismMiddleware(req, res, {
    price: 0.01, // $0.01 USD
    description: "Premium API",
  });

  if (!paymentResult) return; // Middleware handled response

  // Payment verified
  res.status(200).json({
    message: "Premium content",
    payer: (req as any).payer,
  });
}
```

***

## Configuration

### App Router Options

```typescript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
interface PrismRouteConfig {
  identifyToken: string;
  baseUrl?: string;
  debug?: boolean;
  price: number | string; // USD price
  description: string;
  mimeType?: string;
}
```

### Pages Router Options

```typescript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
interface PrismMiddlewareConfig {
  identifyToken: string;
  baseUrl?: string;
  debug?: boolean;
}

interface RoutePaymentConfig {
  price: number | string;
  description: string;
  mimeType?: string;
}
```

***

## App Router Routes

### Single Route

```typescript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
// app/api/premium/route.ts
import { withPrismPayment } from "@1stdigital/prism-nextjs";

async function handler(request: NextRequest) {
  return NextResponse.json({ data: "Premium" });
}

export const GET = withPrismPayment(handler, {
  identifyToken: process.env.PRISM_IDENTIFY_TOKEN!,
  price: 0.01,
  description: "Premium API",
});
```

### Multiple Methods

```typescript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
// app/api/data/route.ts
import { withPrismPayment } from "@1stdigital/prism-nextjs";

async function getHandler(request: NextRequest) {
  return NextResponse.json({ data: "GET data" });
}

async function postHandler(request: NextRequest) {
  const body = await request.json();
  return NextResponse.json({ received: body });
}

export const GET = withPrismPayment(getHandler, {
  identifyToken: process.env.PRISM_IDENTIFY_TOKEN!,
  price: 0.01,
  description: "Get data",
});

export const POST = withPrismPayment(postHandler, {
  identifyToken: process.env.PRISM_IDENTIFY_TOKEN!,
  price: 0.02,
  description: "Post data",
});
```

***

## Accessing Payment Info

### App Router

```typescript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
async function handler(request: NextRequest) {
  // Payer address attached to request
  const payer = (request as any).payer;
  // '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'

  // Payment object in custom property
  const payment = (request as any).prismPayment;

  return NextResponse.json({
    message: "Data",
    payer,
    network: payment?.network,
  });
}
```

### Pages Router

```typescript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  const paymentResult = await prismMiddleware(req, res, {
    price: 0.01,
    description: "Premium",
  });

  if (!paymentResult) return;

  // Access payer
  const payer = (req as any).payer;
  const payment = (res as any).locals?.payment;

  res.json({ payer, network: payment?.network });
}
```

***

## Settlement Validation

<Info>
  **Coming soon: transaction hash in the `X-PAYMENT-RESPONSE` response header.** The Next.js SDK currently confirms settlement internally before returning the response, but does not yet surface the transaction hash to the client. If your application needs the on-chain transaction hash on the client side, use the [Express SDK](/prism/sdk/typescript/express) — it returns this header today.
</Info>

Next.js wraps the Response object to validate settlement:

```typescript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
// Internal implementation (automatic!)
async function withPrismPayment(handler, config) {
  return async (request: NextRequest) => {
    // ... payment validation ...

    // Execute handler
    const response = await handler(request);

    // Validate settlement before returning
    const settlementResult = await core.settlementCallback(...);

    if (!settlementResult || !settlementResult.success) {
      // ❌ Settlement failed
      return NextResponse.json(
        { error: 'Payment settlement failed' },
        { status: 402 }
      );
    }

    // ✅ Settlement succeeded
    response.headers.set('X-PAYMENT-RESPONSE', settlementResult.transaction);
    return response;
  };
}
```

***

## Testing

```typescript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
import { NextRequest } from "next/server";
import { GET } from "./app/api/premium/route";

describe("Next.js Payment Routes", () => {
  it("returns 402 without payment", async () => {
    const request = new NextRequest("http://localhost:3000/api/premium");
    const response = await GET(request);

    expect(response.status).toBe(402);

    const body = await response.json();
    expect(body.paymentRequired).toBe(true);
  });

  it("returns 200 with valid payment", async () => {
    const payment = JSON.stringify({
      scheme: "eip3009",
      signature: "0x" + "0".repeat(130),
    });

    const request = new NextRequest("http://localhost:3000/api/premium", {
      headers: { "X-PAYMENT": payment },
    });

    const response = await GET(request);
    expect(response.status).toBe(200);

    const body = await response.json();
    expect(body.message).toBe("Premium content");
  });
});
```

***

## Production Deployment

```typescript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
// next.config.js
module.exports = {
  env: {
    PRISM_IDENTIFY_TOKEN: process.env.PRISM_IDENTIFY_TOKEN,
    PRISM_BASE_URL: process.env.PRISM_BASE_URL
  },

  // Enable edge runtime (optional)
  experimental: {
    runtime: 'edge'
  }
};

// Vercel deployment
// vercel.json
{
  "env": {
    "PRISM_IDENTIFY_TOKEN": "@prism-identify-token",
    "PRISM_BASE_URL": "@prism-base-url"
  }
}
```
