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

# Step 2: Server-side setup

> Create a Next.js API route that fetches an ElevenLabs signed URL and returns an Anam session token while keeping API keys on the server.

Complete [step one: Agent configuration](/docs/integrations/elevenlabs/agent-configuration) first. In this step, add the server route that connects your ElevenLabs agent to Anam.

## Prerequisites

* Node.js 20.9+
* A Next.js project using the App Router, or the [demo project](https://github.com/anam-org/anam-cookbook/tree/main/examples/elevenlabs-server-side-agent-nextjs)
* An [Anam](https://anam.ai) account and API key (sign up free at [lab.anam.ai](https://lab.anam.ai))
* A Cara 4 avatar from the Anam Lab Avatars page
* An [ElevenLabs](https://elevenlabs.io) account with a Conversational AI agent configured via the dashboard

## Create the server route

You need one API route. It fetches a signed URL from ElevenLabs, then passes it to Anam when creating a session token.

API keys stay server-side. The client sends only the `avatarId` (which face to render) and `agentId` (which ElevenLabs agent to use).

### Environment variables

```bash theme={"system"}
ANAM_API_KEY=your_anam_api_key
ELEVENLABS_API_KEY=your_elevenlabs_api_key
```

### API route

```typescript theme={"system"}
// app/api/anam-session/route.ts
import { NextResponse } from "next/server";

export async function POST(request: Request) {
  const anamApiKey = process.env.ANAM_API_KEY;
  if (!anamApiKey) {
    return NextResponse.json(
      { error: "ANAM_API_KEY must be set" },
      { status: 500 }
    );
  }

  const elevenLabsApiKey = process.env.ELEVENLABS_API_KEY;
  if (!elevenLabsApiKey) {
    return NextResponse.json(
      { error: "ELEVENLABS_API_KEY must be set" },
      { status: 500 }
    );
  }

  const body = await request.json().catch(() => ({}));
  const { avatarId, agentId } = body;

  if (!avatarId) {
    return NextResponse.json(
      { error: "avatarId is required" },
      { status: 400 }
    );
  }
  if (!agentId) {
    return NextResponse.json(
      { error: "agentId is required" },
      { status: 400 }
    );
  }

  // 1. Get a signed URL from ElevenLabs
  const elRes = await fetch(
    `https://api.elevenlabs.io/v1/convai/conversation/get-signed-url?agent_id=${agentId}`,
    {
      headers: { "xi-api-key": elevenLabsApiKey },
    }
  );

  if (!elRes.ok) {
    const text = await elRes.text();
    return NextResponse.json(
      { error: `ElevenLabs API error: ${elRes.status} ${text}` },
      { status: elRes.status }
    );
  }

  const { signed_url: signedUrl } = await elRes.json();

  // 2. Create an Anam session token with the ElevenLabs agent settings
  const anamRes = await fetch("https://api.anam.ai/v1/auth/session-token", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${anamApiKey}`,
    },
    body: JSON.stringify({
      personaConfig: {
        avatarId,
        avatarModel: "cara-4",
        directorNotes: {
          presetStyle: "warm",
          expressivity: 0.5,
        },
      },
      environment: {
        elevenLabsAgentSettings: {
          signedUrl,
          agentId,
        },
      },
    }),
  });

  if (!anamRes.ok) {
    const text = await anamRes.text();
    return NextResponse.json(
      { error: `Anam API error: ${anamRes.status} ${text}` },
      { status: anamRes.status }
    );
  }

  const data = await anamRes.json();
  return NextResponse.json({ sessionToken: data.sessionToken });
}
```

The `environment.elevenLabsAgentSettings` field configures ElevenLabs as the session's speech recognition, language model, and text-to-speech provider. `avatarModel` and `directorNotes` enable a warm Cara 4 performance at the start of the session.

<Info>
  The signed URL is short-lived (typically valid for 15 minutes). Anam uses it immediately when the client connects, so there's no issue with expiry in normal usage. If you're pre-fetching tokens, create them just before the client needs them.
</Info>

Your server route is ready. Next, start an avatar session in your browser.

<Card title="Step 3: Start the avatar session" icon="arrow-right" href="/docs/integrations/elevenlabs/start-session">
  Connect the browser, enable your microphone, and have your first conversation with the avatar.
</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.