> ## 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.

# SmartAI Assessment

> Plug-and-play AI-proctored assessment platform. Integrate in minutes using our backend and frontend packages.

## What is SmartAI Assessment?

SmartAI Assessment lets you embed a fully-proctored, AI-generated assessment portal directly inside your own application. You install a backend package and a frontend package — the platform handles everything else.

| Package                                  | Runs on                | Language   | Purpose                                 |
| ---------------------------------------- | ---------------------- | ---------- | --------------------------------------- |
| `@recordorg/smartai-assessment-backend`  | Your server            | Node.js    | Creates session tokens, polls results   |
| `smartai-assessment-backend`             | Your server            | Python     | Creates session tokens, polls results   |
| `@recordorg/smartai-assessment-frontend` | Your web app (browser) | JavaScript | Opens the assessment modal in an iframe |

***

## How the flow works

```
YOUR APPLICATION
│
├─ 1. Recruiter selects candidates and clicks "SmartAI Assessment"
│
├─ 2. Frontend calls your backend:
│      POST /assessment/session
│      { users: [{ name, email }, ...] }
│
├─ 3. Your backend calls SmartAI SDK:
│      client.createSession({ users, recruiterId?, recruiterEmail? })
│      ◀── { token }
│
├─ 4. Your backend returns the token to the frontend
│
├─ 5. Frontend opens the portal:
│      AssessmentPortal.open({ token, apiKey })
│      ══► full-screen iframe loads — candidate takes the test
│
├─ 6. Candidate finishes the assessment inside the iframe
│
├─ 7. Your backend polls results every 30 s:
│      client.getWebhookEvents({ limit: 50 })
│      ◀── { events, pendingCount }
│
└─ 8. Save results → client.acknowledgeWebhookEvents([...ids])
```

***

## Quick start

### 1. Get your API keys

Log into the SmartAI dashboard and copy your **API key** and **Secret key**.

* Prefix `VFN_TEST_` → **test / staging** environment
* Prefix `VFN_LIVE_` → **live / production** environment

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

***

### 2. Install backend package

<CodeGroup>
  ```bash Node.js theme={null}
  npm install @recordorg/smartai-assessment-backend
  ```

  ```bash Python theme={null}
  pip install smartai-assessment-backend
  ```
</CodeGroup>

### 3. Install frontend package

```bash theme={null}
npm install @recordorg/smartai-assessment-frontend
```

***

### 4. Add a session endpoint to your backend

<CodeGroup>
  ```typescript 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,
    });

    // users — array of { name, email }
    const { users, recruiterId, recruiterEmail } = req.body;

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

    if (!recruiterId && !recruiterEmail) {
      return res.status(400).json({ success: false, message: 'Provide at least one of recruiterId or recruiterEmail' });
    }

    const session = await client.createSession({
      users,           // [{ name, email }, ...]
      recruiterId,     // optional — pass one or both
      recruiterEmail,  // optional — pass one or both
    });

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

  ```python 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_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,         # pass recruiter_id
          recruiter_email=body.recruiter_email,   # or recruiter_email — at least one required
      )
      return {"success": True, "data": session}
  ```
</CodeGroup>

***

### 5. Open the portal from your frontend

Add `NEXT_PUBLIC_ASSESSMENT_API_KEY` to your frontend `.env.local`:

```bash theme={null}
NEXT_PUBLIC_ASSESSMENT_API_KEY=VFN_TEST_your_key_here
```

Then in your component, call your backend first to get the token, then open the portal:

```typescript theme={null}
// 1. Call YOUR backend to get a session token
const response = await assessmentApi.createSession(users);
const token  = response?.data?.token;
const apiKey = process.env.NEXT_PUBLIC_ASSESSMENT_API_KEY;

// 2. Open the portal (dynamic import required for Next.js)
const { default: AssessmentPortal } = await import('@recordorg/smartai-assessment-frontend');

AssessmentPortal.open({
  token,
  apiKey,
  onDone:  () => toast.success('Assessment sent successfully!'),
  onClose: () => {},
  onError: (err: Error) => toast.error(err.message || 'Assessment failed'),
});
```

***

### 6. Poll for results in the background

<CodeGroup>
  ```typescript Node.js theme={null}
  async function pollResults() {
    const client = new AssessmentClient({
      apiKey:    process.env.ASSESSMENT_API_KEY,
      secretKey: process.env.ASSESSMENT_SECRET_KEY,
    });

    const { events } = await client.getWebhookEvents({ limit: 50 });

    for (const event of events) {
      await saveToDatabase(event);
    }

    if (events.length) {
      await client.acknowledgeWebhookEvents(events.map(e => e.eventId));
    }
  }

  setInterval(pollResults, 30_000);
  pollResults();
  ```

  ```python Python theme={null}
  import time
  from smartai_assessment_backend import AssessmentClient
  import os

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

  def poll_results():
      try:
          has_more = True
          while has_more:
              result = client.get_webhook_events(limit=50)
              events = result.get("events", [])
              pending_count = result.get("pendingCount", 0)

              for event in events:
                  save_to_database(event)

              if events:
                  client.acknowledge_webhook_events([e["eventId"] for e in events])

              has_more = pending_count > 0
      except Exception as err:
          print(f"Poll failed: {err}")

  while True:
      poll_results()
      time.sleep(30)  # every 30 seconds
  ```
</CodeGroup>

***

## Integration checklist

<Check>API key and secret key set as environment variables on your server</Check>
<Check>Backend session endpoint created and protected by your own auth middleware</Check>
<Check>Frontend calls your session endpoint before opening the portal</Check>
<Check>`AssessmentPortal.open()` receives the token from your backend</Check>
<Check>`onDone` and `onError` callbacks implemented</Check>
<Check>Background poller running `getWebhookEvents()` every 30 seconds</Check>
<Check>Results saved to your database with idempotent upsert on `eventId`</Check>
<Check>`acknowledgeWebhookEvents()` called after every successful save batch</Check>
