Select Version Type

[V2] BYO (Bring Your Own) Auth + Chat

Designed for products with their own backend and authentication, this version gives you full control over user onboarding, syncing, and logout while seamlessly integrating powerful Sageion capabilities.

Prerequisite

  1. Sign up / log in to your Sageion account.
  2. Create a New App and select Version V2 during setup.
  3. Open the App Details page and note your: App Name, API Key, and Region (US or IN).

Project setup

Client Side Integration

Sageion boots in two ordered phases: setUp() prepares configuration and storage, and initialize() authenticates the user and mounts the chat UI. Pick your framework below, then pick the integration style that matches your app's structure.

⚠️ Lifecycle contract — read before you split anything

  1. setUp() must resolve before initialize() is called. initialize() reads the setup_done flag written by setUp() and refuses to run without it.
  2. Both functions throw a SageionSetupError on failure. Each also renders an error popup with a Reset Settings button.
  3. Never place setUp() and initialize() in two independent DOMContentLoaded listeners. DOM listeners do not chain await — initialize() will fire while setUp() is still in flight, and the SDK will reject it with "initialize ran before setUp could finish."
  4. To split them across scripts, bridge them with a shared promise (see the Two-Block tab).
You can inspect the current phase at any time with window.sageion_os.getSetupStatus(), which returns one of: "idle" | "pending" | "done" | "failed".
1. Load The Scripts
<script src="https://cdn.socket.io/4.1.2/socket.io.min.js"></script>
<script src="https://magicchat-core.github.io/dev-sscc-client-cdns/bundle.js"></script>

SDK global

Loading the bundle exposes window.sageion_os. Every example below uses that global.

2. Decide how to place the Sageion chat box in your app.

Pick your framework below. Inside each framework, choose the integration style that matches your app's structure.
Plain HTML + JavaScript. Choose one of the three integration styles below.

Single-Block Implementation

One async flow, both calls awaited in order. This is the simplest, safest setup and is what most apps should use.
Use this when your app has a single entry HTML file and the chat box should appear across all routes.
<script>
  (async () => {
    try {
      await window.sageion_os.setUp(
        "your_app_name",                 // app_name
        "YOUR_API_KEY",                  // api_key (base64)
        "US",                            // region: "US" | "IN"
        "sageion-chat-root"              // chat_root_id (optional)
      );

      // Optional: resolve uid from your own auth
      const token = localStorage.getItem("token");
      let payload = {};
      if (token) {
        const res = await fetch(`${window.__APP_CONFIG__.API_BASE_URL}/auth/profile`, {
          headers: { Authorization: `Bearer ${token}` }
        });
        if (res.ok) {
          const user = await res.json();
          payload = { uid: user.id.toString() };
        } else {
          localStorage.removeItem("token");
        }
      }

      await window.sageion_os.initialize(payload);

      console.log("Sageion ready. Status:", window.sageion_os.getSetupStatus());
    } catch (err) {
      // The SDK already rendered an error popup. Log for diagnostics only.
      console.error("[Sageion] bootstrap failed:", err);
    }
  })();
</script>

Minimal form

Only the first three arguments are required. chat_root_id has a sensible default — most apps can simply write:
await window.sageion_os.setUp("your_app_name", "YOUR_API_KEY", "US");

Don't split across two DOMContentLoaded listeners

Two separate document.addEventListener("DOMContentLoaded", …) blocks do not chain their awaits. initialize() will run before setUp() resolves and the SDK will reject it. If you need two blocks, use the Two-Block tab.

Parameter Details — setUp()

ParameterTypeRequiredDescription
app_namestringYesUnique application identifier.
api_keystringYesBase64-encoded API key from App Details.
regionstringYes"US" or "IN" — used as the config lookup prefix.
chat_root_idstringNoOptional DOM element id to mount the chat into. Falls back to document.body.

Parameter Details — initialize()

FieldTypeDescription
payload.uidstringRequired when dont_show_chat_box_at_logout is enabled for your app.

Upgrading from a previous SDK version

Earlier versions of the SDK accepted extra arguments (header_req, version). Both have been removed. If you were passing them, drop them and keep only the arguments shown above.
Old callNew call
setUp(name, key, region, false, "chat-root")setUp(name, key, region, "chat-root")
setUp(name, key, region, false)setUp(name, key, region)
setUp(name, key, region)setUp(name, key, region) (unchanged)

Handling login & logout at runtime

setUp() runs once per page load. It does not re-run when the user logs in or out in place. To reflect auth changes without a page reload, call initialize() again with the new uid, or call logout().
// After a successful login (no page reload):
async function onLogin(user) {
  await window.sageion_os.initialize({ uid: user.id.toString() });
}

// On logout:
function onLogout() {
  window.sageion_os.logout();  // clears SDK storage, disconnects sockets, resets state
  // To re-open the chat as anonymous immediately:
  // await window.sageion_os.initialize();
}

Failure reference

Both setUp() and initialize() throw a SageionSetupError on failure. The four most common messages are:
ErrorCauseFix
Wrong `api_key` found in credentialsapi_key in your config does not match the cached auth_keyCorrect the key, then click Reset Settings in the error popup (or call sageion_os.logout())
The current domain (X) is not authorizedYour hostname is not in the app's whitelabel_domainsAsk your Sageion admin to add the domain
initialize ran before setUp could finishinitialize() was called before setUp() resolved — usually from two independent DOMContentLoaded listenersUse Single-Block or Two-Block from the tabs above
initialize skipped: setUp failed earliersetUp() failed and you still called initialize()Fix the underlying setUp() failure. The original error popup is still on screen.

Example Implementations

View complete working implementations on GitHub:

Connecting Sageion to Your Product's Authentication

Sageion does not own your user identities. Your product remains the source of truth — users sign up and log in against your own backend, and Sageion is told about them via a small onboarding call. This page shows the full flow end-to-end.

🔑 How identity flows

  1. A user signs up in your app. Your backend creates the user record and returns its own token.
  2. Your backend calls Sageion's onboarding endpoint with the user's uid and your app_name. This maps the user into Sageion.
  3. On the frontend, your app calls initialize({ uid }) with the same uid. Sageion now knows which of its users this is.
  4. When the user logs out, your app calls window.sageion_os.logout() so Sageion clears the session.

UID is the only link

The uid you pass to onboarding must match the uid you pass to initialize() exactly. Sageion has no other way to know which of your users is which. Use your own users.id, users.uid, or another stable unique key — just be consistent.

Onboarding API

The onboarding endpoint registers a user with Sageion so they can appear in the Admin Panel and use the chat box.
POST https://{region}.userauth2.tezkit.com/dev/onboarding
Replace {region} with your Sageion region — either us or in. It's the same value you pass as region to setUp() on the frontend.

Headers

HeaderValueWhere to get it
X-API-KeyYour Sageion REST API keySageion Admin Panel → App Details → REST API Key
Content-Typeapplication/jsonAlways this value

Body

FieldTypeRequiredDescription
uidstringYesYour platform's unique user identifier, as a string. Must match what you pass to initialize() on the frontend.
app_namestringYesYour registered Sageion application name (from App Details).

Example request

curl --location 'https://us.userauth2.tezkit.com/dev/onboarding' \
  --header 'X-API-Key: YOUR_REST_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "uid": "12345",
    "app_name": "your_application_name"
  }'

Response

A successful onboarding returns HTTP 200 with a small confirmation payload. Once onboarded, the user appears under Users in the Sageion Admin Panel for that app.

Response contract — status codes only

The onboarding response body is not read by Sageion. What matters is the status code: 2xx means the user is onboarded. If the user was already onboarded, your handler should still return 2xx — onboarding is idempotent. On failure, return 4xx or 5xx so your own retry logic can detect it. Because the client SDK treats any 2xx as success, do not return 200 on failure.

Where to call onboarding

Onboarding must be called exactly once per user, ideally the moment your own signup succeeds. Pick your backend language below, then choose the onboarding method that matches your workflow.
Express + axios. This is the reference implementation used by Sageion's own sample app.

Backend onboarding (Node.js)

Call onboarding inside your /register handler, right after your own user row is created. It's fire-and-forget: your signup succeeds even if onboarding fails.
// routes/auth.js
const axios = require('axios');

router.post('/register', [...validators], async (req, res) => {
  const { email, password, full_name } = req.body;

  // 1. Create the user in your own DB
  const hashed = await hashPassword(password);
  const result = await pool.query(
    'INSERT INTO users (email, password_hash, full_name) VALUES ($1, $2, $3) RETURNING id, email, full_name, role',
    [email, hashed, full_name]
  );
  const user = result.rows[0];

  // 2. Onboard the user into Sageion (fire-and-forget)
  try {
    const onboardingUrl = `https://${process.env.SAGEION_REGION}.userauth2.tezkit.com/dev/onboarding`;
    await axios.post(
      onboardingUrl,
      {
        uid: user.id.toString(),
        app_name: process.env.SAGEION_APP_NAME,
      },
      {
        headers: {
          'X-API-Key': process.env.SAGEION_REST_API_KEY,
          'Content-Type': 'application/json',
        },
        timeout: 5000,
      }
    );
  } catch (onboardErr) {
    // Do NOT fail registration — the user can still log in and use your app.
    // The chat box just won't work for this user until they're onboarded.
    console.error('Sageion onboarding error:', onboardErr.message);
  }

  // 3. Return your own token — Sageion does not issue auth tokens
  const token = generateToken(user.id, user.email, user.role);
  res.status(201).json({ token, user });
});

Onboarding failure is silent by design

If the onboarding call fails, registration still succeeds. Your user exists in your DB but not in Sageion — the chat box won't work for them until they're onboarded. Add an alert or a background retry so you notice.

What onboarded users look like

Once a user is onboarded, they appear in the Sageion Admin Panel under your application, ready for chat. Applications without any onboarded users show an empty state.
1

Admin Panel — users present

Sageion Admin Panel showing onboarded users
2

Admin Panel — no users yet

Sageion Admin Panel showing no onboarded users

Logout cleanup

Because authentication is handled by your own product, you must tell Sageion when a user logs out. Otherwise the chat session persists and the chat box may remain visible after logout.

Always call logout on the client

This is a frontend-only call. Sageion does not expose a server-side logout endpoint — the SDK clears its own storage and disconnects its sockets when you invoke it.
// In your client-side logout handler:
window.sageion_os.logout?.();

// It:
//   - clears all tezkit_* keys from localStorage
//   - disconnects the active socket and AI socket
//   - resets setupStatus back to "idle"
// After logout, call initialize() again to re-open the chat as anonymous.

APIs the AI agent can call — sync vs. async

Every API you register with Sageion falls into one of two categories, depending on how quickly it can produce its final result. Pick the one that matches the nature of the endpoint — most APIs are synchronous, and you only reach for async when the final result genuinely cannot be produced within the request lifecycle.
Synchronous (default)Asynchronous (Async Callback enabled)
When to useThe endpoint can compute and return the final result within a few seconds of the request.The endpoint cannot produce the final result immediately — it depends on a payment gateway, an approval, a background job, or an external event.
How the agent gets the resultReads it from the HTTP response body.Waits for your backend to POST the final result to Sageion's webhook callback URL.
What your handler doesDoes the work, returns the final result.Acknowledges the request, kicks off the work, returns early — then POSTs the final result via webhook when it's ready.
What Sageion sendsNothing extra.An x-correlation-id header on the initial request.
Where the config livesNothing to configure — this is the default.Enable Async Callback when registering the API in the Sageion Admin Panel.

One endpoint, one nature

An endpoint is either synchronous or asynchronous — it does not switch between the two at runtime. The example code below uses an if (correlation_id) branch purely to illustrate both paths on one screen; a real integration picks one and sticks with it. If your API is synchronous, you never read x-correlation-id. If it's asynchronous, Sageion always sends it (because you enabled Async Callback for that API) and your handler always uses it.

Path A — Synchronous API

You write your handler exactly as you would for any normal API. Sageion calls your endpoint, waits for the response, and uses the body as the final result. No special headers to read, no webhook to post — nothing.
// Example: a bookings endpoint that confirms the reservation inline.
// This is what a synchronous API looks like — no correlation_id, no webhook.

router.post('/bookings', [...validators], async (req, res) => {
  const { room_id, check_in, check_out } = req.body;
  const user_id = req.user.userId;

  // Do the work and return the final result. That's it.
  const booking = await createBooking(user_id, room_id, check_in, check_out);
  res.status(201).json({
    success: true,
    booking_id: booking.id,
    status: booking.status,
  });
});

You're done

If your API is synchronous, that's all you need to know. Everything that follows in this section is for the async case only.

Path B — Asynchronous API (Async Callback enabled)

You register the API in the Sageion Admin Panel with Async Callback enabled. From then on, Sageion attaches an x-correlation-id header to every request to that endpoint and treats your initial response as an acknowledgment, not as the final answer.

🔄 When async is the right choice

  • The action depends on a payment gateway — the user pays, then the gateway confirms minutes later.
  • The action depends on a human approval that happens out-of-band (a manager clicks approve).
  • The action kicks off a multi-step workflow in your own system whose completion is signalled by a separate event.
  • The action needs to send the user an email or SMS and wait for a response before it can produce a final result.
If none of these apply — if your backend can compute the final result by the time the request handler returns — use the synchronous path instead. Async adds complexity, and there's no reason to reach for it prematurely.
How the async flow works
1

Sageion sends the request with x-correlation-id

Because the API is configured with Async Callback enabled, Sageion attaches an x-correlation-id header to every call. This header is the only thing that distinguishes an async-configured call from a synchronous one.
2

Your handler acknowledges the request and kicks off the work

Read req.headers['x-correlation-id'], start whatever needs to happen (send a payment link, queue a job, notify another service), and respond immediately — usually with HTTP 202 and any interim data the user should see. Do not wait for the async work to complete inside the handler.
3

Later — when the work completes — your backend POSTs to Sageion's webhook

Once the async operation finishes (payment confirmed, job complete, external system replied), your backend — or the external service's own webhook handler in your code — POSTs a JSON body containing the same correlation_id and the final data to Sageion's webhook callback URL.
4

Sageion matches the correlation_id and resumes the workflow

The workflow engine pairs the callback with the original request, resumes execution, and passes the data you sent into the next step.
Request header: x-correlation-id
HeaderTypeDescription
x-correlation-idstringSent by Sageion on every request to an API configured with Async Callback. Your handler reads it and echoes it back in the webhook payload so the callback can be matched to the original request.
Webhook callback contract
POST https://{region}.autobot2.tezkit.com/dev/webhook/callback
This is Sageion's webhook receiver. Your backend posts here when the async operation completes. The URL and environment suffix vary by region — use the one configured in your Admin Panel's webhook settings.
FieldTypeRequiredDescription
correlation_idstringYesThe exact x-correlation-id value Sageion sent in the original request. Used to match the callback to the workflow step.
dataobjectYesThe final payload the workflow engine should receive as the API response. Any JSON shape is allowed — Sageion passes it through to the next step.

Response format is a contract — match it exactly

  • correlation_id must be the verbatim string from the request header. Do not reformat, prefix, or wrap it.
  • data must be a top-level object, not a string. Wrapping the payload in JSON.stringify() before posting will break parsing.
  • The webhook POST should return 2xx. Sageion retries on non-2xx responses, so return 200 immediately after your handler acknowledges the callback — do not delay on downstream work.
  • Extra top-level fields beyond correlation_id and data are ignored.
Worked example — a booking that waits on payment
Consider a hotel booking API. When the user asks to book a room, the API does not confirm the booking immediately — instead, it emails a payment link. The booking only becomes confirmed once the payment gateway reports success, which happens minutes later. This is the textbook case for async: the final result genuinely cannot be produced within the request lifecycle.
Below are the same booking endpoint written both ways, so you can see exactly where the async pattern diverges. The synchronous version confirms the booking inline and returns. The async version acknowledges the request, sends the payment link, and produces the final result later via the payment provider's webhook handler.
The endpoint does everything up front and returns the confirmed booking. Sageion reads the result from the HTTP response body. No x-correlation-id is present, no webhook is involved.
// routes/bookings.js — SYNC booking (confirms immediately)
router.post('/', [...validators], async (req, res) => {
  const { room_id, check_in, check_out } = req.body;
  const user_id = req.user.userId;

  // Do all the work now and return the final result.
  const booking = await createBooking(user_id, room_id, check_in, check_out);

  res.status(201).json({
    success: true,
    booking_id: booking.id,
    status: 'confirmed',
  });
});
Async handler — reference implementations
The concept is identical across languages: read x-correlation-id, return early, then POST the final result to Sageion's webhook callback when the async work finishes. Below are minimal reference implementations.
// routes/orders.js — async order submission
const axios = require('axios');

router.post('/orders', async (req, res) => {
  const correlation_id = req.headers['x-correlation-id'];

  // Kick off the long-running work (queue a job, call an external system).
  const order = await createPendingOrder(req.body);
  await attachCorrelationId(order.id, correlation_id);

  // Return early.
  res.status(202).json({ success: true, order_id: order.id, status: 'processing' });

  // ... elsewhere, when the work finishes:
  // await axios.post(
  //   `https://${process.env.SAGEION_REGION}.autobot2.tezkit.com/dev/webhook/callback`,
  //   {
  //     correlation_id,
  //     data: { success: true, order_id: order.id, status: 'completed' },
  //   }
  // );
});

✅ Checklist for async APIs

  1. Enable Async Callback in the Sageion Admin Panel when you register the API. Without this, Sageion sends no x-correlation-id and your handler will not know a webhook is expected.
  2. Read x-correlation-id at the very top of the handler, before any branch that could return early.
  3. Persist the correlation_id alongside the entity the async work is about (order, booking, job). You will need it in a completely different request later.
  4. Respond to the initial request quickly — 2xx with any interim data. Do not wait for the async work inside the original handler.
  5. When the async work finishes, POST to Sageion's webhook callback with the same correlation_id, verbatim, and a data object containing the final result.
  6. Log the correlation_id at every step of your pipeline. It is the only way to correlate Sageion's original request with your eventual callback.

Environment variables

Your backend needs these variables. Add them to your server's environment — never expose SAGEION_REST_API_KEY or SAGEION_CLIENT_SECRET to the browser.
VariableExampleUsed for
SAGEION_REGIONusRegional prefix in the onboarding URL and webhook callback URL.
SAGEION_APP_NAMEai_chatbot_systemIdentifies your Sageion app in onboarding and agent-token requests.
SAGEION_REST_API_KEYyour_rest_api_keyX-API-Key header for onboarding.
SAGEION_CLIENT_SECRETyour_client_secretVerifies client credentials on /client-user-token (only needed if you enable the optional AI agent section below). Never expose to the browser.
WEBHOOK_CALLBACK_URLhttps://us.autobot2.tezkit.com/dev/webhook/callbackWhere your backend posts async results for APIs configured with webhook enabled.

✅ Base integration checklist

  1. Trigger onboarding immediately after your own user is created — inside the same signup handler, not in a background job.
  2. Treat onboarding failures as non-fatal to signup, but log them and add an alert so you notice missing users.
  3. Use the exact same uid in onboarding and in initialize({ uid }) — they must match for the chat box to work.
  4. Always call window.sageion_os.logout() from your own logout handler, before clearing your own session.
  5. Never ship SAGEION_CLIENT_SECRET or SAGEION_REST_API_KEY to the frontend. If you use the frontend onboarding method, use a different token scoped to onboarding only.
  6. For bulk onboarding of existing users, contact Sageion Support before calling the API in a loop.
Once all six items above are done, your Sageion integration is complete. The next section is optional and can be added at any time.

Binding the AI agent to a user for authenticated API access (Optional)

📌 Optional — add this whenever you need it

You do not need this section to get Sageion's chat box running. Your users can chat with the AI agent without it. Set it up only when you want the AI agent to access protected endpoints on your own backend — for example, to fetch or modify a specific user's bookings on their behalf.
You can do this during your initial integration from day one, or add it later when the need arises — nothing on this page conflicts with anything above.

⚠️ Response format is a contract — match it exactly

For the AI agent to successfully call your /auth/client-user-token, /auth/send-otp, and /auth/verify-otp endpoints, your handlers must return responses in the exact shape documented below. The workflow engine reads specific field names from each response — it does not adapt to renames, extra wrappers, or missing fields.
  • Do not wrap responses in { data: { ... } } or { result: { ... } } — return the fields at the top level.
  • Do not rename fields. token must be token, user_id must be user_id, scope must be scope, expires_in must be expires_in.
  • Do not omit fields. expires_in and scope are read by the client to decide token freshness and permitted actions.
  • Extra fields beyond the ones documented are allowed and will be ignored.
  • Status codes matter: 200 for success, 401 for invalid client credentials, 404 for unknown user. The workflow engine branches on these codes.

What problem does this solve?

By default, the AI agent talks to your backend as a generic client. If your backend exposes user-scoped endpoints (like GET /bookings/me), the agent has no way to prove who it's acting for — so it can't reach those endpoints.
This integration closes that gap. Your backend exchanges its client credentials for a short-lived, scoped token tied to a specific user. The agent then calls your authenticated endpoints as that user.

🧩 When you need this

  • Your AI workflows call your own backend APIs on behalf of a logged-in user
  • You want fine-grained scopes (read, create, update, cancel) rather than blanket access
  • You want short-lived tokens (1 hour) rather than long-lived user sessions

1. Agent token endpoint (/auth/client-user-token)

Your backend exposes this endpoint. It accepts the client credentials plus a user id, verifies both, and returns a short-lived JWT the agent can use.
POST /auth/client-user-token
FieldTypeRequiredDescription
client_idstringYesYour Sageion app_name.
client_secretstringYesYour Sageion client secret. Keep this server-side only.
user_idstringYesThe user's id from your platform. Must be numeric.
session_idstringNoOptional session identifier to correlate token usage.
Response:
FieldTypeDescription
tokenstringShort-lived JWT the agent uses for subsequent calls.
expires_innumberSeconds until expiry — currently 3600.
scopestring[]Actions authorized by the token. Currently: booking:read, booking:create, booking:update, booking:cancel.
user_idstringEcho of the user_id the token was issued for.

Response contract — required fields

FieldTypeRequiredWhy it matters
tokenstringYesThe JWT the agent attaches as a Bearer token. Missing or null → the agent cannot make authenticated calls.
expires_innumberYesSeconds until expiry. If omitted, the agent cannot tell when to refresh the token.
scopestring[]YesThe list of actions this token authorizes. The agent checks this list before attempting operations.
user_idstringYesEcho of the user_id the token was issued for. The agent uses it to verify the token is bound to the right user.
Return this object at the top level with HTTP 200. On failure, return HTTP 401 (invalid client credentials) or HTTP 404 (user not found) with a plain JSON body — the agent treats non-2xx responses as refusals, not as retryable errors.
Reference implementation by language

Backend handler — Node.js

// routes/auth.js

const SAGEION_APP_NAME = process.env.SAGEION_APP_NAME;
const SAGEION_CLIENT_SECRET = process.env.SAGEION_CLIENT_SECRET;

router.post('/client-user-token', [
  body('client_id').notEmpty(),
  body('client_secret').notEmpty(),
  body('user_id').notEmpty().isInt(),
  body('session_id').optional().isString(),
], async (req, res) => {
  const { client_id, client_secret, user_id, session_id } = req.body;

  // 1. Verify client credentials
  if (client_id !== SAGEION_APP_NAME || client_secret !== SAGEION_CLIENT_SECRET) {
    return res.status(401).json({ error: 'Invalid client credentials' });
  }

  // 2. Verify the user exists
  const check = await pool.query('SELECT id FROM users WHERE id = $1', [user_id]);
  if (check.rows.length === 0) {
    return res.status(404).json({ error: 'User not found' });
  }

  // 3. Issue a scoped, short-lived token
  const scopes = [
    'booking:read', 'booking:create', 'booking:update', 'booking:cancel',
  ];
  const token = generateToken(user_id, 'client@system', 'client', {
    scope: scopes,
    client_id,
    session_id,
  });

  res.json({ token, expires_in: 3600, scope: scopes, user_id });
});
Calling it from your agent workflow (Node.js)
const axios = require('axios');

async function getAgentToken(userId) {
  const { data } = await axios.post(
    `${process.env.API_BASE_URL}/auth/client-user-token`,
    {
      client_id: process.env.SAGEION_APP_NAME,
      client_secret: process.env.SAGEION_CLIENT_SECRET,
      user_id: String(userId),
    }
  );
  return data.token; // use as Bearer token for agent-initiated calls
}

2. OTP endpoints (/auth/send-otp, /auth/verify-otp)

Two endpoints back an OTP flow, useful when an action triggered from chat needs a second factor of confirmation — for example, cancelling a booking.

OTP is not your login

These endpoints verify one-off actions. They are separate from your main login flow and do not issue a session token.
2a. Send OTP — POST /auth/send-otp
FieldTypeRequiredDescription
emailstringYesEmail address the OTP is associated with.
Generates a 6-digit OTP, stores it against the email, and expires it after 5 minutes. The reference implementation logs the OTP — plug in your own email provider for delivery.

Response contract — required fields

FieldTypeRequiredWhy it matters
successbooleanYesThe workflow engine checks this to decide whether to proceed to the verification step.
Return this object at the top level with HTTP 200. If sending fails (bad email, provider outage), return HTTP 400 or 500 — do not return 200 with success: false, because the workflow engine treats 2xx as authoritative.
Reference implementation by language — /send-otp
// routes/auth.js — send OTP
router.post('/send-otp', [
  body('email').isEmail().normalizeEmail(),
], async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() });

  const { email } = req.body;
  const otp = Math.floor(100000 + Math.random() * 900000).toString();
  const expiresAt = new Date(Date.now() + 5 * 60 * 1000); // 5 min

  try {
    await pool.query(
      `INSERT INTO otps (email, otp, expires_at) VALUES ($1, $2, $3)
       ON CONFLICT (email) DO UPDATE SET otp = $2, expires_at = $3`,
      [email, otp, expiresAt]
    );
    // TODO: send via your email provider
    console.log(`[OTP] Sent OTP ${otp} to ${email}`);
    res.json({ success: true, message: 'OTP sent' });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Server error' });
  }
});
2b. Verify OTP — POST /auth/verify-otp
FieldTypeRequiredDescription
emailstringYesThe email the OTP was sent to.
otpstringYesThe 6-digit code the user entered.
On success, returns { success: true, user_id } so the workflow can continue with the verified identity. The OTP record is deleted after verification.

Response contract — required fields

FieldTypeRequiredWhy it matters
successbooleanYesThe workflow engine checks this to allow the OTP-gated action to proceed.
user_idstringYesThe verified user's id. The workflow continues with this identity — omitting it breaks any downstream user-scoped call.
Return this object at the top level with HTTP 200. On verification failure, return HTTP 400 with a plain JSON body.

user_id must be a string

JSON numbers lose leading zeros and can be represented inconsistently across languages (JavaScript numbers, Go int64, Python int). To keep the identity check reliable, always return user_id as a JSON string — for example "user_id": "12345" — even if your database column is an integer.
Reference implementation by language — /verify-otp
// routes/auth.js — verify OTP
router.post('/verify-otp', [
  body('email').isEmail().normalizeEmail(),
  body('otp').isLength({ min: 6, max: 6 }).matches(/^\d+$/),
], async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() });

  const { email, otp } = req.body;
  try {
    const result = await pool.query(
      'SELECT otp, expires_at FROM otps WHERE email = $1',
      [email]
    );
    if (result.rows.length === 0) {
      return res.status(400).json({ error: 'No OTP request found' });
    }
    const record = result.rows[0];
    if (record.otp !== otp) {
      return res.status(400).json({ error: 'Invalid OTP' });
    }
    if (new Date() > new Date(record.expires_at)) {
      return res.status(400).json({ error: 'OTP expired' });
    }

    const userResult = await pool.query(
      'SELECT id FROM users WHERE email = $1', [email]
    );
    if (userResult.rows.length === 0) {
      return res.status(404).json({ error: 'User not found' });
    }
    const userId = userResult.rows[0].id;

    await pool.query('DELETE FROM otps WHERE email = $1', [email]);

    res.json({
      success: true,
      message: 'OTP verified successfully',
      user_id: userId.toString(),
    });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Server error' });
  }
});

✅ You're done with the base integration

Everything above the "Binding the AI agent to a user" section is what you need to get Sageion working. Everything from that section onward is additive — nothing there is required for the chat box to work.

Platform

The Sageion Admin Platform provides comprehensive tools for managing your chat applications, users, and system settings. Below is an overview of the key sections available in the Admin UI.

Global Level Settings

These settings apply across all applications within your tenant, providing centralized control over system-wide configurations.

🔐 Admin Access Required

Only users with ADMIN or MANAGER role have access to these settings. If you don't see these options, contact your system administrator.

Global Tenant Settings

The Global Tenant Settings page allows administrators to configure tenant-wide features that affect all applications under the tenant.
Enables email notifications at various useful events across all applications. This toggle controls whether email alerts are sent for key system events.
📧 Available Notification Triggers
TriggerDescriptionAvailability
FIRST MSG ON ANY APPTriggers when the first message arrives on any app since admin went offlineAll Plans
FIRST MSG ON EVERY APPTriggers when the first message arrives on every app since admin went offline📌 ADVANCE Plan Only

Configuration Options

Email notifications can be customized per event type. Configure which events trigger emails and the recipient list in the settings panel.

Plan Restriction

"FIRST MSG ON EVERY APP" is only available on the ADVANCE plan. Upgrade your plan to access this feature.

Invite Support User

Invite team members as support users with granular permission controls. This feature allows you to add users with specific roles and permissions to manage your applications.

📌 Multi-Admin Required

The Invite Support User feature requires Multi-Admin to be enabled in Global Tenant Settings first. This ensures proper permission hierarchy and security.
👤 User Roles
RoleAccess LevelPrimary Responsibilities
MANAGERFull AccessManage applications, settings, and users
DEVELOPERTechnical AccessAPI configuration, workflows, and technical settings
CUSTOMER_CARE_EXECUTIVELimited AccessAll Chats and user management

Role Assignment

Users can be assigned multiple roles. The combination of roles determines the user's overall permissions.
💡 Best Practice
Assign the minimum required roles to each user to maintain security best practices.

Whitelabel Domains

Configure custom domains for your applications to maintain brand consistency. This allows you to serve the Sageion chat interface from your own domain.
Available Features
  1. Add custom domain names for your applications
  2. SSL certificate management
  3. DNS configuration guidance

DNS Configuration Guide

To set up a custom domain:
  1. Add your domain in the Whitelabel Domains section
  2. Configure DNS records as instructed
  3. Wait for DNS propagation (24-48 hours)
  4. Verify the domain and enable SSL

✅ Setup Complete

Once configured, your chat interface will be served from your custom domain, providing a seamless brand experience for your users.

FAQ Chat & Lead Generation

The FAQ Chat & Lead Generation section provides powerful tools for building interactive FAQ trees, managing leads, and capturing visitor information through forms.

LeadGen & FAQ

This feature combines two powerful capabilities: Interactive FAQ/Q&A Trees and Lead Generation.

Two Modes

  1. FAQ/Q&A Tree Mode: Build hierarchical question-answer structures
  2. Lead Generation Mode: Capture leads at any node in the tree
🌳 FAQ Tree Builder
The Dynamic Tree Builder allows you to create structured FAQ content:
  1. Create hierarchical question-answer trees
  2. Add sub-questions and answers
  3. Attach lead generation forms at any node
  4. Enable/disable the FAQ bot content

⚠️ At Least One Chatbot Required

You must have at least one chatbot enabled at all times. The system validates that either AI Chat, Live Agent, or FAQ Bot is active. You cannot disable all chatbots simultaneously.
🎯 Lead Generation Management
Capture and manage leads from your FAQ forms and other sources:
  1. View all captured leads with timestamps and metadata
  2. Export leads to XLSX or CSV format
  3. Leads are automatically stored in the Admin Panel
  4. Connect to external servers via AI Agent workflows
Lead FieldDescription
Lead IDUnique identifier for each lead
TimestampWhen the lead was captured
Lead DataForm fields and user responses
MetadataAdditional context (source, page, etc.)
📝 Bot Forms & Post-Processing
Configure how forms behave and what happens after submission:
Template TypeDescriptionUse Case
THANK_YOUShows appreciation messageSimple thank you response
GET_BACK_TO_YOU_SHORTLYInforms about follow-upLead qualification

Lead Storage Options

  1. Built-in Storage: Leads stored in Sageion Admin Panel under Lead Generation section
  2. External Integration: Send to external servers via orchestrated AI Agent workflows
🔧 Form Field Configuration
Each form can have multiple fields with the following properties:
Field PropertyDescriptionExample
LabelDisplay nameEmail Address
TypeField typetext, email, phone, etc.
RequiredWhether field is mandatorytrue/false
PlaceholderHint textEnter your email

✅ Best Practice

Keep lead capture forms short and focused on essential information to maximize conversion rates.
🔄 Update Process
When updating LeadGen & FAQ settings:
  1. Make your changes to the FAQ tree or lead settings
  2. Click the 'Update' button at the bottom
  3. Review the confirmation modal (all clients will be rebooted)
  4. Confirm to apply changes

⚠️ Client Reboot Warning

Updating LeadGen & FAQ settings will reboot all active clients to sync the new configuration.

✅ FAQ Chat & Lead Generation Overview Complete

The LeadGen & FAQ feature provides a complete solution for building interactive FAQ trees and capturing leads from your website visitors.

Live Agent

The Live Agent feature enables real-time human-to-human chat support, allowing you to interact directly with your website visitors and provide personalized assistance.

Live Agent Features

Configure all aspects of your Live Agent experience including enabling/disabling, user capacity, chat appearance, messaging, and updates.
Site Users represent the total number of unique visitors who can register and interact with your Live Agent. Each registered user consumes one slot from your capacity.
📊 Understanding Your Capacity
MetricDescription
Plan LimitBase number of user slots included in your plan
Top-ups AddedAdditional slots purchased through top-ups
Total CapacityPlan Limit + Top-ups Added
Available SlotsRemaining slots available for new users
  1. Progress bar shows remaining capacity percentage
  2. Low capacity warning appears when below 20%
  3. Critical warning appears when 0 slots remain

🔄 How Site Users Work

Each unique visitor who registers or starts a chat session consumes one user slot. Slots are not released until the user is explicitly removed or the session expires.
👥 Top-Up Options
When you're running low on user slots, you can purchase additional capacity:
Slots AddedPriceCost Per Slot
+125 Slots₹1,500~₹12 per slot
+250 Slots₹3,000~₹12 per slot
+375 Slots₹4,500~₹12 per slot

💡 Pro Tip

Top-ups are added permanently to your total capacity. Consider purchasing larger packages for better value if you expect high user growth.

✅ Live Agent Overview Complete

The Live Agent feature provides real-time human chat support for your website visitors. Enable it to offer personalized assistance and improve customer satisfaction.
Monitor your Site Users capacity regularly and top up when needed to ensure you never run out of slots for new users.

AI Chat

The AI Chat feature provides intelligent conversational AI capabilities for your website, enabling automated customer support, lead qualification, and information retrieval using advanced language models.

AI Chat Features

Configure all aspects of your AI Chat experience including enabling/disabling, message credits, ingestion storage, data sources, and training.
The AI Agent bot provides automated conversational AI capabilities for your website visitors.
How to Enable
  1. Navigate to AI Chat settings from the sidebar
  2. Toggle the 'Enable AI Agent Bot' switch to ON
  3. All AI agent settings will appear below
  4. Configure your data sources and training
  5. Click 'Update AI Chat' to save changes

🤖 What the AI Agent Can Do

  1. Answer customer questions 24/7
  2. Qualify leads through conversation
  3. Retrieve information from your knowledge base
  4. Escalate complex issues to human agents

⚠️ At Least One Chatbot Required

You must have at least one chatbot enabled at all times. The system validates that either AI Chat, QnA (LeadGen) Bot, or Live Agent is active. You cannot disable all chatbots simultaneously.

✅ AI Chat Overview Complete

The AI Chat feature provides intelligent conversational AI for your website. Enable it to automate customer support, qualify leads, and provide 24/7 assistance.
Monitor your AI message credits and ingestion storage regularly. Top up when needed and retrain your AI Agent with fresh data to keep responses accurate and relevant.

All Chat

The All Chat feature provides a comprehensive real-time messaging interface for agents to communicate with site visitors, manage conversations, and provide support across all applications.

All Chat Features

The All Chat interface provides a complete messaging solution for support agents, including user management, real-time messaging, file sharing, and conversation history.
The All Chat interface is divided into two main sections: the left sidebar showing all users and the right panel displaying the active conversation.
📱 Interface Layout
SectionDescriptionKey Features
Left SidebarDisplays all users across all applicationsUser list, online status, unread counts, app grouping
Right PanelShows the active conversationMessage history, typing indicator, message input, file upload
  1. Users are grouped by application for easy navigation
  2. Each user shows their name, online status, and unread message count
  3. Click on a user to open the conversation
  4. The chat header displays the user's name and online status
All Chat Interface Overview

💡 Quick Navigation

Use the 'Back to Users' button in the chat header to return to the user list. The 'Refresh' button at the top reloads the entire user list.

✅ All Chat Overview Complete

The All Chat feature provides a complete real-time messaging solution for support agents. It includes user management, file sharing, message reactions.
Use the All Chat interface to manage all your support conversations in one place, across all applications and regions.

Integrations & APIs & Workflows

The Integrations & APIs & Workflows section provides comprehensive tools for configuring API connections, building multi-step workflows, and managing response templates for your chatbot applications.

API Config

The API Config section allows you to define and manage API endpoints that your chatbot can call. Each API configuration includes authentication, request structure, and response handling.
Configure authentication for your APIs to securely connect to backend services.
Primary Authentication (Login Server)
  1. Configure the login server that provides access tokens
  2. Must NOT contain an Authorization header (system adds it automatically)
  3. Payload must include: client_secret, user_id, client_id
  4. Only one Primary Authentication setup per application
Step 1: Send Verification Code (OTP)
  1. Send a one-time password (OTP) to the user's email or phone
  2. Must NOT contain an Authorization header
  3. Used for multi-factor authentication flows
Step 2: Verify Code & Get User ID
  1. Verify the OTP and return the authenticated user_id
  2. Must NOT contain an Authorization header
  3. The user_id returned is used for all subsequent API calls

💡 Authentication Flow

The authentication flow typically follows: Login Server → (Token) → API Calls. For multi-factor auth, add Step 1 (Send Code) and Step 2 (Verify Code) before the main API calls.

ChainApis

ChainApis enables you to create multi-step API workflows where the response from one API determines the next API to call. This is useful for complex business logic that requires multiple steps.
A Chain is a sequence of API calls where each step can branch based on the response status of the previous step.
Chain Structure
  1. Root API: The first API call in the chain
  2. Branches: Follow-up APIs triggered by specific response statuses
  3. Each branch can have its own field mappings
  4. Chains can be enabled/disabled
Root API: /api/check_availability (Status: 200)
  → Branch (Success): /api/book_room
  → Branch (404): /api/notify_unavailable

💡 When to Use Chains

Use Chains when you need to handle complex, multi-step workflows. For example: Check Availability → (Success) Book Room → (Failure) Suggest Alternatives.

Response Settings

Response Settings allows you to manage response templates across all API configurations in one centralized location.
Centrally manage all response templates for your API configurations.
Template Features
  1. View and edit templates for each API config
  2. Create templates for multiple status codes
  3. Preview rendered messages
  4. Use Jinja syntax with field autocomplete

📌 Centralized Management

Response Settings provides a single view of all templates across your API configurations. This makes it easy to maintain consistent messaging across your chatbot.

✅ Integrations & APIs & Workflows Overview Complete

The Integrations & APIs & Workflows section provides a complete toolkit for connecting your chatbot to backend services, building complex workflows, and managing user-facing responses.
Start by configuring your APIs, then build chains for complex workflows, and finally design user-friendly response templates to create a seamless user experience.

Visual Response Designer

The Visual Response Designer is a powerful no-code tool that lets you design exactly how your AI responses appear to users. Build stunning, interactive screens without writing a single line of code.

What is the Visual Response Designer?

The Visual Response Designer is a drag-and-drop interface that transforms raw API responses into beautiful, user-friendly messages. It's designed for product managers, support teams, and developers who want full control over their chat experience without writing code.

💡 Why Use the Visual Response Designer?

  • ✅ No coding required — design visually, just like building a slide
  • ✅ See exactly what your users will see, in real-time
  • ✅ Transform data into tables, cards, lists, and styled text with one click
  • ✅ Perfect for customer support teams, product managers, and non-technical users

Key Concepts

Understanding these core concepts will help you get started quickly:
📄 Screen
A Screen is what your users see in the chat. Each screen can display different information. You can create:
  • Single Screen: All data appears on one screen (perfect for simple responses)
  • Multiple Screens: Each data item appears on its own screen (great for lists, search results, or multi-item responses)
📋 Template
A Template is the design of your response. It defines what information appears and how it's organized. Think of it like a slide design in PowerPoint — you design once, and it works for all your data.
🔄 Transformations
Transformations are visual enhancements you can apply to your design with one click:
  • 📊 Table View — Show data in a clean, organized table
  • 🃏 Card View — Display each item as a beautiful card
  • 📋 List View — Show items in a simple list format
  • 🎨 Style Transformations — Highlight, bold, italicize, or underline text

Getting Started

Follow these steps to create your first visual response:
1

Step 1: Paste Your Sample Response

Copy a sample JSON response from your API and paste it into the 'Sample Response' area. This gives the designer an example of your data structure.

💡 Tip

Use a real response from your API to see exactly how your data will appear. The designer automatically generates a starting template from your sample.
2

Step 2: Click 'Render Preview'

This generates a visual preview of your response. You'll see how your data looks and can start designing.
3

Step 3: Open the Visual Editor

Click 'Open Editor' to access the visual design interface. Here you can:
  • Drag rows to reorder content
  • Edit text directly inline
  • Add custom messages
  • Insert dynamic data fields
4

Step 4: Apply Transformations

Use the 'Start Wizard' button to transform your design:
  • Structure — Convert to Table, Cards, or List view
  • Media — Turn image URLs into actual pictures
  • Styles — Apply colors, bold, italic, and alignment
5

Step 5: Save Your Design

Click 'Use Template' or 'Save Configuration' to save your visual design. It's now ready for your users!

The Visual Editor

The Visual Editor is where you design your responses. It's designed to be intuitive and powerful, like a slide editor:
🖱️ Drag & Drop Reordering
Simply drag any row up or down to change the order of content. Your changes are reflected instantly in the preview.
✏️ Inline Editing
Click the ✎ icon on any row to edit its content directly. You can:
  • Change text labels
  • Add custom messages
  • Insert dynamic data using the @ menu
➕ Add Buttons & Button Groups
Add interactive elements to your responses:
  • Single Buttons — Perfect for simple actions like 'Book Now' or 'Learn More'
  • Button Groups — Multiple buttons in a row for related actions

💡 Pro Tip

Use Button Groups to offer users choices. Each button can trigger different actions, like 'View Details', 'Book Now', or 'Contact Support'.

The Transformation Wizard

The Transformation Wizard is your creative toolkit for enhancing responses. It walks you through three steps:
Change how your data is organized and displayed:
TransformationWhat It DoesBest For
📊 Table ViewOrganizes data into a clean table with headers and rowsComparing multiple items, structured data
🃏 Card ViewShows each item as a separate card with a title and detailsProfiles, product listings, individual records
📋 List ViewSimple list format with each item on a new lineQuick overviews, short lists
📝 JSON ViewShows the raw data structureDebugging and technical reviews

💡 Card View Options

Card View can be displayed vertically (scrolling down) or horizontally (scrolling sideways). Choose the direction that best fits your content.

Single Screen vs Multiple Screens

The Visual Response Designer automatically detects your data structure and suggests the best layout:
Layout TypeWhen It's UsedWhat Users SeeExample
Single ScreenYour data has a single item or metadata with arraysAll information on one screenA hotel booking confirmation with guest details
Multiple ScreensYour data has a list of items at the root or in an arrayEach item appears on its own screenA list of available rooms, each with its own screen

💡 How It Works

The designer analyzes your data structure automatically. If you have a list of items, you'll get multiple screens. If you have a single object, you'll get a single screen. You can always adjust the design manually.

Live Preview

The Visual Response Designer shows you exactly what your users will see, updated in real-time as you design:
  • 👁️ See your changes instantly — no refresh needed
  • 📱 Preview in Desktop or Mobile view
  • 🔄 See how your design looks with different data
  • ✅ Ensure everything looks perfect before saving

💡 Pro Tip

Use the Desktop/Mobile toggle to test how your design looks on different devices. This ensures a great experience for all users.

Saving & Deployment

Once your design is ready, saving it is simple:
1

Review Your Design

Check the preview to ensure everything looks perfect.
2

Click 'Use Template'

This saves your design to the configuration. If you're in the standalone tool, click 'Save Configuration'.
3

Deploy to Users

Your visual design is now live! Users will see the beautiful, professional responses you've created.

⚠️ Important

When you save a design, all active clients (users) will be updated automatically to see the new response format.

Best Practices

Follow these tips to create the best user experience:
  • 💡 Start simple — begin with a basic design and add complexity gradually
  • 📱 Test on mobile — always preview your design in mobile view
  • 🎯 Be consistent — use similar styles across all responses for brand coherence
  • 📊 Use Card View for multi-item responses to improve readability
  • 🎨 Apply styles sparingly — highlight only what's truly important
  • 🔘 Use buttons to guide users to the next action

✅ Visual Response Designer Overview Complete

The Visual Response Designer is a no-code tool that empowers you to create beautiful, professional responses without writing code. Whether you're a product manager, support lead, or developer, you can design exactly what users see in the chat.
Start with your sample data, design visually, and deploy to users instantly. No coding required.

Congratulations! Your integration should now be successful!

Your users can now sign up and seamlessly chat with the Admin Team, enabling two-way communication.

Please contact our Support Team if you encounter any issues. Thank you!