# Short-lived Avatar Tokens (Advanced)

### When should I use this?

* You do not want to expose your Sentifyd `AVATAR_API_KEY` in JavaScript or in a static HTML file.
* Your site already calls your own backend before rendering most pages (typical SSR / Next.js, remix, Flask, Rails, etc.).
* You need full control over who may request a token (e.g. only logged-in customers).

If you simply need to embed a public avatar on a static site, consider the **no-backend** integration described in the *Quick Start* guide instead.

### 1 — Add an endpoint in your backend

Create a lightweight route that:

1. Receives a **GET** (or POST) from the browser.
2. Calls the Sentifyd Authentication API with your **`AVATAR_API_KEY`**.
3. Returns a JSON payload containing:
   * an `accessToken` (JWT)
   * a `refreshToken`
   * `avatarParameters` (theme, voice, etc.)

#### Reference endpoint implementation

{% tabs %}
{% tab title="Python (Flask)" %}

```
from flask import Blueprint, current_app, jsonify, request
import requests

blueprint = Blueprint("sentifyd", __name__)

@blueprint.route("/request_tokens", methods=["GET"])
def request_tokens():
    sentifyd_backend_url = current_app.config["SENTIFYD_BACKEND"] + "/api/login"
    avatar_api_key = current_app.config["AVATAR_API_KEY"]

    payload = {"avatar_api_key": avatar_api_key}
    try:
        response = requests.post(sentifyd_backend_url, json=payload)
        if response.status_code != 200:
            return jsonify({"error": "Authentication failed", "details": response.json()}), response.status_code

        data = response.json()["data"]
        frontend_payload = {
            "tokens": {
                "accessToken": data["access_token"],
                "refreshToken": data["refresh_token"],
            },
            "avatarParameters": data["avatar_params"],
        }
        return jsonify(frontend_payload), 200

    except Exception as e:
        current_app.logger.exception("Error while requesting Sentifyd tokens")
        return jsonify({"error": "Internal server error"}), 500
```

{% endtab %}

{% tab title="Typescript (Express.js)" %}

```
import express, { Request, Response } from "express";
import axios from "axios";

const router = express.Router();

// Example configuration values (could also come from process.env)
const SENTIFYD_BACKEND = process.env.SENTIFYD_BACKEND || "https://backend.sentifyd.io";
const AVATAR_API_KEY = process.env.AVATAR_API_KEY || "your-avatar-api-key-here";

router.get("/request_tokens", async (req: Request, res: Response) => {
  const sentifydBackendUrl = `${SENTIFYD_BACKEND}/api/login`;
  const payload = { avatar_api_key: AVATAR_API_KEY };

  try {
    const response = await axios.post(sentifydBackendUrl, payload);

    if (response.status !== 200) {
      return res.status(response.status).json({
        error: "Authentication failed",
        details: response.data,
      });
    }

    const data = response.data.data;
    const frontendPayload = {
      tokens: {
        accessToken: data.access_token,
        refreshToken: data.refresh_token,
      },
      avatarParameters: data.avatar_params,
    };

    return res.status(200).json(frontendPayload);
  } catch (error: any) {
    console.error("Error while requesting Sentifyd tokens:", error);
    return res.status(500).json({ error: "Internal server error" });
  }
});

export default router;

```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
**Secure config :** store `AVATAR_API_KEY` and `SENTIFYD_BACKEND` in environment variables or a secrets store—never commit them to git.
{% endhint %}

**Tips**

* **Cache** the refresh token server‑side if you have many concurrent clients; this reduces traffic to Sentifyd.
* Make sure CORS allows your own origin (`Access‑Control‑Allow‑Origin`).
* Add auth middleware if only signed‑in users may chat with the avatar.

### 2 — Serve the Sentifyd web component

1. Load the Sentifyd component loader **once** on every page that needs an avatar:

```
<script src="https://frontend.sentifyd.io/sentifyd-bot/main.js" defer></script>
```

2. Place the `<sentifyd-bot>` element where you want the avatar to appear. Provide **both** the URL of the endpoint you just created *and* the `avatar_id` you received from the Sentifyd dashboard.

```
<sentifyd-bot
    token_endpoint="https://your-backend.com/request_tokens"
    avatar_id="YOUR-AVATAR-ID">
</sentifyd-bot>
```

* `token_endpoint` — full, publicly reachable URL of the route that returns the JSON payload shown above.
* `avatar_id` — the unique identifier of the avatar you created in the Sentifyd console.

> **Avoid duplicates:** keep each attribute only once; browsers ignore later duplicates.

***

### 3 — How it works

1. The web component boots and issues a **GET** to `token_endpoint`.
2. Your backend exchanges the `AVATAR_API_KEY` for fresh tokens.
3. The frontend receives `{ tokens, avatarParameters }` and opens a WebSocket to Sentifyd.
4. When the access token expires, the component transparently calls your endpoint again with `?refreshToken=...`.

***

### 4 — Minimal example (static HTML)

```
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Sentifyd BFF demo</title>
    <script src="https://cdn.sentifyd.io/element/bot.js" defer></script>
  </head>
  <body>
    <h1>Hello, Sentifyd!</h1>

    <sentifyd-bot
      token_endpoint="https://demo.example.com/request_tokens"
      avatar_id="avtr_1234abcd">
    </sentifyd-bot>
  </body>
</html>
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sentifyd.io/manual-web-integration/short-lived-avatar-tokens-advanced.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
