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

# Set Up a Next.js App Router API Proxy for ParaLens

> Create a Next.js App Router API route that proxies requests to ParaLens, keeping your base URL private and enabling future API key support.

The easiest way to integrate ParaLens into a Next.js app is to create an API route that proxies requests. This hides the Railway URL from client-side code, forwards future API keys securely via server-side environment variables, and gives you a single place to add caching or logging as your app grows.

## Prerequisites

* **Next.js 13+** with the App Router (`app/` directory)
* **TypeScript** (recommended — types shown throughout this guide)

## Setup

<Steps>
  <Step title="Create the API route file">
    Create a new file at `app/api/analyze/route.ts`. Next.js will automatically expose this as `POST /api/analyze` when the app is running.

    ```ts theme={null}
    // app/api/analyze/route.ts
    export async function POST(request: Request) {
      const body = await request.json();

      const response = await fetch(`${process.env.PARALENS_API_URL}/analyze`, {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify(body),
        cache: 'no-store',
      });

      const data = await response.json();
      return Response.json(data, { status: response.status });
    }
    ```

    The route reads `PARALENS_API_URL` from the server environment and forwards the request body as-is. The upstream HTTP status is preserved so your frontend error handling works correctly.
  </Step>

  <Step title="Add the environment variable">
    Add the Railway base URL to `.env.local`. This file is read only by Next.js server-side code and is never included in the client bundle.

    ```bash theme={null}
    # .env.local
    PARALENS_API_URL=https://paralens-production.up.railway.app
    ```

    <Warning>
      Never prefix this variable with `NEXT_PUBLIC_`. Public variables are embedded in the client bundle and visible to anyone who inspects your JavaScript. Keep the Railway URL server-side only.
    </Warning>
  </Step>

  <Step title="Call the proxy from your frontend">
    In any client component, call `/api/analyze` instead of the Railway URL directly.

    ```ts theme={null}
    // lib/analyze.ts
    import type { TxReport } from '@/types/paralens';

    export async function analyze(txHash: string): Promise<TxReport> {
      const response = await fetch('/api/analyze', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ chain: 'ethereum', tx_hash: txHash }),
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.error ?? 'Analysis failed');
      }

      return response.json(); // TxReport
    }
    ```
  </Step>

  <Step title="(Optional) Add response caching">
    Ethereum transactions are immutable once confirmed, so the same hash will always produce the same report. Add caching at the proxy layer to avoid redundant upstream calls.

    See the [Adding Caching](#adding-caching) section below for an in-memory and Redis example.
  </Step>
</Steps>

## Adding Caching

Because confirmed transactions never change, you can safely cache responses indefinitely. A 24-hour TTL is a practical default that balances freshness with performance.

**In-memory cache** — suitable for single-instance deployments or development:

```ts theme={null}
// app/api/analyze/route.ts
const cache = new Map<string, { data: unknown; expiresAt: number }>();
const TTL_MS = 24 * 60 * 60 * 1000; // 24 hours

export async function POST(request: Request) {
  const body = await request.json();
  const cacheKey = `${body.chain}:${body.tx_hash}`;

  const cached = cache.get(cacheKey);
  if (cached && Date.now() < cached.expiresAt) {
    return Response.json(cached.data);
  }

  const response = await fetch(`${process.env.PARALENS_API_URL}/analyze`, {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify(body),
    cache: 'no-store',
  });

  const data = await response.json();

  if (response.ok) {
    cache.set(cacheKey, { data, expiresAt: Date.now() + TTL_MS });
  }

  return Response.json(data, { status: response.status });
}
```

**Redis cache** — recommended for multi-instance or serverless deployments (e.g., Vercel). Use `ioredis` or the `@upstash/redis` client:

```ts theme={null}
// app/api/analyze/route.ts
import { Redis } from '@upstash/redis';

const redis = Redis.fromEnv();
const TTL_SECONDS = 86400; // 24 hours

export async function POST(request: Request) {
  const body = await request.json();
  const cacheKey = `paralens:${body.chain}:${body.tx_hash}`;

  const cached = await redis.get(cacheKey);
  if (cached) {
    return Response.json(cached);
  }

  const response = await fetch(`${process.env.PARALENS_API_URL}/analyze`, {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify(body),
    cache: 'no-store',
  });

  const data = await response.json();

  if (response.ok) {
    await redis.set(cacheKey, data, { ex: TTL_SECONDS });
  }

  return Response.json(data, { status: response.status });
}
```

## Future API Key Support

ParaLens does not require authentication today, but future-compatible clients should be prepared to send an `x-api-key` header. When API keys are introduced, update your proxy to read `PARALENS_API_KEY` from the server environment and forward it — no changes needed in your frontend components.

```ts theme={null}
// app/api/analyze/route.ts
const response = await fetch(`${process.env.PARALENS_API_URL}/analyze`, {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    ...(process.env.PARALENS_API_KEY && { 'x-api-key': process.env.PARALENS_API_KEY }),
  },
  body: JSON.stringify(body),
  cache: 'no-store',
});
```

Add the key to `.env.local` when you receive one:

```bash theme={null}
# .env.local
PARALENS_API_URL=https://paralens-production.up.railway.app
PARALENS_API_KEY=your-api-key-here
```

<Note>
  Never expose your Railway URL or API key in client-side code or public environment variables (i.e., variables prefixed with `NEXT_PUBLIC_`). Always read credentials in server-only code such as API routes, Server Components, or `getServerSideProps`.
</Note>

## Next Steps

Now that your proxy is set up, head to [Dashboard Layouts](/docs/guides/dashboard-layouts) to learn how to use `classification.intent_kind` to choose the right UI layout for each transaction type.
