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

# Starting Sessions

This guide will show you how to start a session and connect to it. At a high level, here's how this process works:

1. Your backend starts a session by calling an authenticated API endpoint and returning session
   credentials to your frontend.
2. Your frontend connects to the session using the session credentials.

## 1. Start a session from your backend

In this section, you'll set up your backend so that it can start sessions by calling Jay's
`startSession` API endpoint.

### 1a. Define your Jay API key as an environment variable

Create a `JAY_API_KEY` environment variable in your local environment (e.g., a `.env` file) and/or
in your production environment (e.g., Vercel, AWS, etc.). In a `.env` file, you might include:

```
JAY_API_KEY=<YOUR_API_KEY>
```

You can retrieve your API key from [Jay's dashboard](https://jay.so/dashboard/agent/settings).

### 1b. Create an API endpoint

Create an API endpoint in your backend for starting the session. We strongly recommend using
authentication in your endpoint to protect your Jay API key and prevent unauthorized users from
starting sessions.

Copy and paste the code below into the API endpoint:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    import requests

    # Your authentication logic goes here:
    # ...

    agent_id = <YOUR_AGENT_ID>
    jay_api_key = os.getenv("JAY_API_KEY")

    url = "https://jay.so/api/startSession"
    headers = {
        "Content-Type": "application/json",
        "X-API-Key": jay_api_key
    }
    payload = {
        "agent_id": agent_id,
        "environment": "production"
    }

    response = requests.post(url, headers=headers, json=payload)

    if not response.ok:
        raise Exception(f"Request failed with status {response.status_code}. {response.text}")

    data = response.json()
    return data
    ```

    In the code above, make sure to replace `<YOUR_AGENT_ID>` with your agent ID, which you can either retrieve from the file containing your agent (e.g. `agent/main.py`) or from [Jay's
    dashboard](https://jay.so/dashboard/agent/settings).

    <Info>
      **Optional**: You can include custom data in the payload, which will be available when the session is configured:

      ```python {4-6} theme={null}
      payload = {
          "agent_id": agent_id,
          "environment": "production",
          "custom_data": {
            "my_user_timezone": "America/New_York",
          }
      }
      ```

      The custom data will be available in the [`custom_data`](https://docs.jay.so/references/configure-session#param-custom-data) input parameter of the `configure_session` function.

      Note: The `custom_data` field must be JSON serializable.
    </Info>
  </Tab>

  <Tab title="Node.js">
    ```js theme={null}
    // Your authentication logic goes here:
    // ...

    const agentId = <YOUR_AGENT_ID>;
    const jayApiKey = process.env.JAY_API_KEY;

    if (!jayApiKey) {
      throw new Error("Your 'JAY_API_KEY' isn't defined.")
    }

    const response = await fetch("https://jay.so/api/startSession", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-API-Key": jayApiKey,
      },
      body: JSON.stringify({
        agent_id: agentId,
        environment: "production",
      })
    });

    if (!response.ok) {
      throw new Error(`Request failed with status ${response.status}. ${await response.text()}`);
    }

    const data = await response.json();
    return res.json(data);
    ```

    In the code above, make sure to replace `<YOUR_AGENT_ID>` with your agent ID, which you can either retrieve from the file containing your agent (e.g. `agent/main.py`) or from [Jay's
    dashboard](https://jay.so/dashboard/agent/settings).

    <Info>
      **Optional**: You can include custom data in the payload, which will be available when the session is configured:

      ```js {4-6} theme={null}
      body: JSON.stringify({
        agent_id: agentId,
        environment: "production",
        custom_data: {
          my_user_timezone: "America/New_York",
        }
      })
      ```

      The custom data will be available in the [`custom_data`](https://docs.jay.so/references/configure-session#param-custom-data) input parameter of the `configure_session` function.

      Note: The `custom_data` field must be JSON serializable.
    </Info>
  </Tab>
</Tabs>

## 2. Connect to the session from your frontend

In your frontend, you'll fetch the session credentials from the backend endpoint that you defined in
step 1. Then, you'll connect to the session using these credentials. We'll use LiveKit to handle the
WebRTC connection.

### 2a. Install LiveKit dependencies

Install the following dependencies:

<CodeGroup>
  ```zsh npm theme={null}
  npm install @livekit/components-react
  ```

  ```zsh pnpm theme={null}
  pnpm add @livekit/components-react
  ```

  ```zsh bun theme={null}
  bun add @livekit/components-react
  ```

  ```zsh yarn theme={null}
  yarn add @livekit/components-react
  ```
</CodeGroup>

### 2b. Connect to the session

The code snippet below is a simple React example that shows how to fetch the session credentials
from your backend, connect to the session using these credentials, and display basic loading and
connection states.

```js theme={null}
import React, { useEffect, useState } from "react";
import {
  LiveKitRoom,
  RoomAudioRenderer,
} from "@livekit/components-react";

export default function MyLiveKitExample() {
  const [sessionCredentials, setSessionCredentials] = useState<{
    token: string;
    url: string;
  } | null>(null);
  const [isFetchingSession, setIsFetchingSession] = useState<boolean>(false);

  useEffect(() => {
    // Fetch the session credentials from your backend
    setIsFetchingSession(true);
    fetch(
      <YOUR_BACKEND_ENDPOINT>, // <-- update this to your real endpoint from step 1
      { method: "POST" }
    )
      .then((res) => res.json())
      .then((data) => {
        setSessionCredentials(data)
      })
      .catch((err) => {
        console.error("Error fetching session:", err);
      })
      .finally(() => {
        setIsFetchingSession(false);
      });
  }, []);

  // Show a loading indicator while we're fetching the session
  if (isFetchingSession) {
    return <div>Fetching session...</div>;
  }

  // If we have no session credentials, let the user know
  if (!sessionCredentials) {
    return <div>Missing session credentials</div>;
  }

  // Once connected, render the LiveKitRoom
  return (
    <LiveKitRoom
      token={sessionCredentials.token}
      serverUrl={sessionCredentials.url}
      audio={true}
      onConnected={() => console.log("Connected!")}
      onDisconnected={() => {
        console.log("Disconnected from LiveKit");
      }}
    >
      <div>Connected! Start speaking to the agent.</div>
      {/* Renders audio for participants in the room */}
      <RoomAudioRenderer />
    </LiveKitRoom>
  );
}
```

In the code above, make sure to replace `<YOUR_BACKEND_ENDPOINT>` with your backend endpoint URL
from step 1.

Here are a couple relevant references from LiveKit's documentation:

* [`LiveKitRoom`](https://docs.livekit.io/reference/components/react/component/livekitroom/#livekitroom):
  Provides the LiveKit room context to all its child components. It provides the room state as a
  React context to all child components, so you don't have to pass it yourself.
* [`RoomAudioRenderer`](https://docs.livekit.io/reference/components/react/component/roomaudiorenderer/#roomaudiorenderer):
  A drop-in solution for adding audio to your app. It takes care of handling audio tracks and makes sure that microphones and screen share are audible.
