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

# Create Session

> Your backend endpoint that creates a session token for the SmartAI portal. Your frontend calls this before opening the assessment.

<Info>
  **You build this endpoint.** The path `/assessment/session` is whatever route you choose in your own app. Internally it calls `client.createSession()` from the Backend SDK and returns the token to your frontend.
</Info>

***

## How it fits in the flow

```
Your Frontend (ProfileList.tsx)
    │
    │  POST /assessment/session
    │  { users: [{ name, email }, ...] }
    │
    ▼
Your Backend (this endpoint)
    │
    │  client.createSession({ users, recruiterId?, recruiterEmail? })
    │
    ▼
SmartAI Platform
    │
    │  { token, expiresAt }
    │
    ▼
Your Backend returns { success: true, data: { token, expiresAt } }
    │
    ▼
Your Frontend calls AssessmentPortal.open({ token })
```

***

## Environment variables required

Add these to your server's `.env` file before this endpoint will work:

```bash theme={null}
ASSESSMENT_API_KEY=VFN_TEST_your_key_here
ASSESSMENT_SECRET_KEY=VFN_SK_TEST_your_secret_here
```

<Warning>
  Never put these in your frontend `.env`. They belong on the server only. Your frontend uses `NEXT_PUBLIC_ASSESSMENT_API_KEY` (the public API key) separately just to tell the portal which environment to use — the secret key never leaves your server.
</Warning>

***

## Request

### Headers

<ParamField header="Authorization" type="string" required>
  Your app's authentication token for the logged-in recruiter. Format: `Bearer <jwt>`.
  Protect this endpoint so only your own recruiter accounts can call it.
</ParamField>

<ParamField header="Content-Type" type="string" required>
  Must be `application/json`.
</ParamField>

### Body

<ParamField body="users" type="array" required>
  Array of candidate objects to include in this assessment session. Must have at least one item.

  <Expandable title="Each user object" defaultOpen>
    <ParamField body="name" type="string" required>
      Candidate's full name. Shown in the assessment UI and result reports.
    </ParamField>

    <ParamField body="email" type="string" required>
      Candidate's email address. Used as the unique identifier on the SmartAI platform. Match on this email when you receive webhook results to find the candidate in your own database.
    </ParamField>
  </Expandable>

  ```json theme={null}
  [
    { "name": "Priya Sharma",  "email": "priya@example.com" },
    { "name": "Rahul Verma",   "email": "rahul@example.com" },
    { "name": "Aisha Khan",    "email": "aisha@example.com" }
  ]
  ```
</ParamField>

<ParamField body="recruiterId" type="string">
  Your internal recruiter ID. Pass this **or** `recruiterEmail` — at least one is required.
</ParamField>

<ParamField body="recruiterEmail" type="string">
  The recruiter's email address. Pass this **or** `recruiterId` — at least one is required.
</ParamField>

***

## Response

<ResponseField name="success" type="boolean">
  `true` when the session was created successfully.
</ResponseField>

<ResponseField name="data" type="object">
  <Expandable title="Session data">
    <ResponseField name="token" type="string">
      A session token. Pass this directly to `AssessmentPortal.open({ token })` in your frontend.

      **Do not store or reuse this token.** Request a fresh one every time a recruiter starts a new session.
    </ResponseField>
  </Expandable>
</ResponseField>

***

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://your-app.com/assessment/session \
    --header 'Authorization: Bearer <recruiter-jwt>' \
    --header 'Content-Type: application/json' \
    --data '{
      "users": [
        { "name": "Priya Sharma",  "email": "priya@example.com" },
        { "name": "Rahul Verma",   "email": "rahul@example.com" },
        { "name": "Aisha Khan",    "email": "aisha@example.com" }
      ]
    }'
  ```

  ```typescript Frontend (your ProfileList.tsx) theme={null}
  // This is exactly how your ProfileList.tsx calls this endpoint
  const response = await assessmentApi.createSession(
    data.map(c => ({
      name:  c.name ?? c.fullName ?? '',
      email: c.email ?? '',
    }))
  );

  const token = response?.data?.token;
  ```

  ```typescript Backend — Node.js (Express) theme={null}
  const AssessmentClient = require('@recordorg/smartai-assessment-backend');

  app.post('/assessment/session', yourAuthMiddleware, async (req, res) => {
    const client = new AssessmentClient({
      apiKey:    process.env.ASSESSMENT_API_KEY,
      secretKey: process.env.ASSESSMENT_SECRET_KEY,
    });

    const { users } = req.body;
    if (!users?.length) {
      return res.status(400).json({ success: false, message: 'No candidates provided' });
    }

    const session = await client.createSession({
      users,
      recruiterId:    req.user?.id,      // pass recruiterId
      recruiterEmail: req.user?.email,   // or recruiterEmail — at least one required
    });

    res.json({ success: true, data: session });
  });
  ```

  ```python Backend — Python (FastAPI) theme={null}
  from fastapi import FastAPI, HTTPException
  from smartai_assessment_backend import AssessmentClient
  from pydantic import BaseModel
  import os

  app = FastAPI()

  client = AssessmentClient(
      api_key=os.getenv("ASSESSMENT_API_KEY"),
      secret_key=os.getenv("ASSESSMENT_SECRET_KEY"),
  )

  class User(BaseModel):
      name: str
      email: str

  class SessionRequest(BaseModel):
      users: list[User]
      recruiter_id: str | None = None
      recruiter_email: str | None = None

  @app.post("/assessment/session")
  def create_assessment_session(body: SessionRequest):
      if not body.users:
          raise HTTPException(status_code=400, detail="No candidates provided")

      if not body.recruiter_id and not body.recruiter_email:
          raise HTTPException(
              status_code=400,
              detail="Provide at least one of recruiter_id or recruiter_email",
          )

      users = [{"name": u.name, "email": u.email} for u in body.users]
      session = client.create_session(
          users=users,
          recruiter_id=body.recruiter_id,
          recruiter_email=body.recruiter_email,
      )
      return {"success": True, "data": session}
  ```
</RequestExample>

<ResponseExample>
  ```json 200 Success theme={null}
  {
    "success": true,
    "data": {
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZXNzaW9uSWQiOiJzZXNzXzAxIn0.HMAC"
    }
  }
  ```

  ```json 400 No candidates theme={null}
  {
    "success": false,
    "message": "No candidates provided"
  }
  ```

  ```json 500 Missing env vars theme={null}
  {
    "success": false,
    "message": "SmartAI assessment credentials are not configured"
  }
  ```
</ResponseExample>

***

## Common mistakes

| Mistake                                         | What happens                   | Fix                                              |
| ----------------------------------------------- | ------------------------------ | ------------------------------------------------ |
| `ASSESSMENT_API_KEY` not set in `.env`          | Returns 500                    | Add the key to your server `.env`                |
| Sending `users: []` empty array                 | Returns 400                    | Make sure candidates are selected before calling |
| Neither `recruiterId` nor `recruiterEmail` sent | Returns 400                    | Pass at least one recruiter field                |
| Calling this from the browser directly          | API key exposed in network tab | Always call through your backend                 |
| Reusing the same token for a second session     | Token expired error            | Always request a fresh token                     |
