Skip to content
AISARAISAR

Embedding AISAR chat

How to embed AISAR's full-featured chat into a third-party application via iframe: authentication, three display modes, and a full integration walkthrough.

AISAR provides an embeddable chat — a full-featured messenger that loads inside an <iframe> in your application. The user works with the chat inside your UI without leaving it.

Architecture

text
Ваше приложение (бэкенд)
    │
    ├─ 1. Создать API-токен           (однократно, через AISAR UI)
    ├─ 2. Получить список юзеров      GET  /v1/users
    ├─ 3. Найти контакт по телефону   GET  /v1/contacts/lookup?q=...
    ├─ 4. Получить список каналов     GET  /v1/channels
    ├─ 5. Отправить сообщение         POST /v1/messages/send
    │
    ├─ 6. Авторизовать юзера          POST /v1/embed/auth
    │     → получить session token
    │
    └─ 7. Открыть iframe
          https://my.aisar.app/embed/chat?token=<session_token>&...

Steps 2–3 are cached on your side. Step 4 runs every time the iframe opens (the token lives 8 hours). Every API request uses the base URL https://api.aisar.app with the /v1 prefix and the Authorization: Bearer <api_token> header, issued once in the AISAR UI (Settings → API tokens; the section is available to companies on a business plan with the API feature enabled). A partner receives the key when a company is connected.

Endpoints

List users

Returns every real user of the company (not service accounts) — use it to map your users to AISAR users.

http
GET /v1/users
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json
Response (200)
{
  "data": [
    {
      "id": 1,
      "name": "Алексей",
      "lastname": "Петров",
      "email": "alexey@company.kz",
      "availability": "online",
      "last_login_at": "2026-03-15T10:30:00.000000Z"
    }
  ]
}

id (used in embed/auth), name, lastname, email, availability (online/offline/away).

Search contacts

Search by phone number, external ID, or username. The result gives you the contact_id used in the iframe URL (mode 3).

http
GET /v1/contacts/lookup?q=<query>
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

q (required, 2–255 chars) searches the contact's phone number (+12025550187), account external ID (12025550187@s.whatsapp.net), and username (alexey_petrov), fuzzy match (ILIKE). Limit: max 20 results, groups and merged contacts are excluded.

Response (200, abridged)
{
  "data": [
    {
      "id": 42,
      "company_id": 1,
      "firstName": "Алексей",
      "lastName": "Петров",
      "displayName": "Алексей Петров",
      "status": "active",
      "phones": [{ "phone": "+12025550187", "type": "mobile" }],
      "contactAccounts": [
        { "id": 10, "account_type": "whatsapp", "external_id": "+12025550187", "is_group": false }
      ],
      "tags": []
    }
  ]
}

List channels

Returns the company's channels available to the current user — to obtain the channel_id needed when sending messages.

http
GET /v1/channels
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

Query parameters (all optional): type (channel type), status (active/inactive), channel_type_id, setup_state, include_setup_drafts (defaults to false).

Send a message

Sends an outbound text message to a contact through the given channel; if the conversation doesn't exist, it is created automatically.

http
POST /v1/messages/send
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json
Content-Type: application/json

{
  "channel_id": 3,
  "recipient": "+12025550187",
  "message_content": "Здравствуйте! Ваш заказ готов."
}

channel_id (required, from GET /v1/channels), recipient (required, the recipient's phone number or external_id, format depends on channel type), message_content (required, max 65,535 chars). Response 200: { "success": true }. The full reference for this endpoint (attachments, voice notes, WhatsApp groups, templates) is in the "Sending messages: endpoint reference" guide.

Embed authorization

Creates a short-lived session token for a specific user — this token is passed in the iframe URL.

http
POST /v1/embed/auth
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json
Content-Type: application/json

{
  "user_id": 1
}
Response (200)
{
  "token": "YOUR_EMBED_SESSION_TOKEN",
  "redirect_url": "https://my.aisar.app/embed/chat"
}
user_id must belong to a real user of the same company as the API token — service accounts and platform administrators are not allowed. token lives 8 hours. Errors: 400 — user_id missing; 403 — the call was made not with the company's full API token but with a narrow token of its service account (for example an embedded-chat token), error: "This token cannot issue embed sessions"; 422 — user not found in the company. Since 2026-09-28 the issued token is bound to the company that minted it: requests with it always run in that company, whatever the user's current company is; it does not work on platform endpoints (403), and PUT /v1/me/current-company to another company answers 403 with error: "token_company_bound". If the user stops being a member of the company, an already issued token stops working too (403).

The issued session token has a limited embed:read scope and lives 8 hours — enough to run the embedded chat, but it does not replace a full API token.

Some endpoints refuse an embed token outright — 403 — regardless of what its scope lists. Currently closed this way: the company-wide analytics dashboard (revenue, deals, conversation and message volumes, per-operator load), call-transcript search (q_in=transcript|all on GET /v1/calls), and the missed-call callback queue (/v1/telephony/callbacks*). The general rule: if a surface returns a company-wide commercial summary or a bulk listing of personal data, a token embedded in someone else's UI cannot reach it — call it from your own backend with a regular API token instead.

CRM-based authorization (Bitrix24 and others)

An alternative mode of POST /v1/embed/auth — for embedding the chat straight from a CRM UI (for example, a Bitrix24 card), when the request is initiated by the app installed in the CRM rather than by your backend with an API token. Instead of user_id, it takes the CRM portal identifier.

http
POST /v1/embed/auth
Accept: application/json
Content-Type: application/json

{
  "type": "bitrix24",
  "member_id": "YOUR_CRM_MEMBER_ID",
  "payload": {
    "AUTH_ID": "PORTAL_ISSUED_ACCESS_TOKEN"
  }
}

type (required, the CRM type: bitrix24, etc.), member_id (required, the CRM portal identifier), payload (required, must be an object — otherwise 400). For bitrix24, payload.AUTH_ID is required and must be a string (otherwise 400): it's an access token the handler uses to verify the caller's identity against the portal itself (user.current). The response is the same { "token": ..., "redirect_url": ... } envelope as in the user_id mode; the token likewise has the embed:read scope and lives 8 hours.

Without an AUTH_ID, with an invalid one, or if the verified CRM user isn't mapped to an AISAR user or is no longer a company member — 422, no token is issued. There is no more fallback to "the company's first user": a missing or empty payload.AUTH_ID used to silently issue that token; now it only produces a refusal. Any b24_user_id sent in payload is ignored — identity cannot be asserted over the wire, only proven by verifying AUTH_ID against the portal.

POST /v1/embed/auth is rate-limited across the whole route: calls carrying a service-account Bearer token (the user_id mode) get up to 120 requests/min per token; anonymous calls in this CRM mode get up to 30 requests/min per IP.

Embedding the iframe

Where you can embed it, and iframe attributes

Since 2026-10-08 the embedded chat https://my.aisar.app/embed/chat?token=... can be placed in an <iframe> on any https site — you do not need to register the domain in AISAR. Without a token in the URL the page refuses to be embedded. The token is issued by the integrator's server: POST /v1/embed/auth with the API key of the company's service account (in the cabinet: Settings, API tokens) and the employee's user_id. The token is bound to that employee and company, grants rights only for running the embedded chat, and lives 8 hours; keep it on the server, never log it, and the page removes the token from the address bar itself after loading.

Recommended iframe attributes: allow="microphone; clipboard-write" (voice messages, calls from the embedded chat, and copying to the clipboard). Better not to set sandbox; if you need it, allow allow-scripts allow-same-origin allow-popups allow-forms allow-downloads.

html
<iframe
  src="https://my.aisar.app/embed/chat?token=<session_token>"
  allow="microphone; clipboard-write"
  style="width: 100%; height: 100%; border: none;"
></iframe>
This rule applies to the chat only. Bitrix24 and amoCRM embed the chat themselves; nothing needs to be configured.

Three display modes

Mode 1 — full chat (inbox). A full-featured messenger with a conversation list, filters, search, and a message panel.

html
<iframe
  src="https://my.aisar.app/embed/chat?token=<session_token>"
  style="width: 100%; height: 100%; border: none;"
></iframe>

Mode 2 — chat with a pre-filled search. The same full chat, but the search box is pre-filled (the search parameter).

html
<iframe
  src="https://my.aisar.app/embed/chat?token=<session_token>&search=+12025550187"
  style="width: 100%; height: 100%; border: none;"
></iframe>

Mode 3 — contact message panel. Only the message panel for a specific contact, with no conversation list or filters — ideal for embedding inside a customer record. Parameters: contact_id (from /v1/contacts/lookup), view=messages. Behaviour: loads the contact's most recent conversation; if there are none, shows an empty state; the panel is fully functional (sending/editing messages, managing the conversation).

html
<iframe
  src="https://my.aisar.app/embed/chat?token=<session_token>&contact_id=42&view=messages"
  style="width: 100%; height: 100%; border: none;"
></iframe>

Additional parameters

ParameterDescription
langInterface language: en, ru, kk. Defaults to ru
contact_idContact ID (without view=messages — filters the conversation list)
deal_idDeal ID — opens the chat in the context of a specific deal

Full integration example (Python)

Initial setup (one-time)
API_TOKEN = "YOUR_API_TOKEN"
API_BASE = "https://api.aisar.app/v1"
EMBED_BASE = "https://my.aisar.app/embed/chat"

headers = {
    "Authorization": f"Bearer {API_TOKEN}",
    "Accept": "application/json",
}

# Получите список пользователей для маппинга
response = requests.get(f"{API_BASE}/users", headers=headers)
aisar_users = response.json()["data"]

user_mapping = {
    "your_user_123": 1,   # Алексей → AISAR user ID 1
    "your_user_456": 2,   # Мария → AISAR user ID 2
}

# Найдите контакты по телефонам (кэшируйте результат)
response = requests.get(
    f"{API_BASE}/contacts/lookup",
    params={"q": "+12025550187"},
    headers=headers,
)
contacts = response.json()["data"]  # contacts[0]["id"] = 42 ← contact_id для iframe
On every iframe open
aisar_user_id = user_mapping["your_user_123"]

response = requests.post(
    f"{API_BASE}/embed/auth",
    json={"user_id": aisar_user_id},
    headers=headers,
)
session_token = response.json()["token"]

# Режим 1: полный чат
iframe_url = f"{EMBED_BASE}?token={session_token}"
# Режим 2: предзаполненный поиск
iframe_url = f"{EMBED_BASE}?token={session_token}&search=+12025550187"
# Режим 3: панель сообщений контакта
iframe_url = f"{EMBED_BASE}?token={session_token}&contact_id=42&view=messages"

Recommendations

Caching

WhatHow often to refresh
API tokenPermanent (until revoked)
User listWhen the team composition changes
Contact mappingOn first lookup + as needed
Session tokenEvery time the iframe opens (lives 8 hours)

iframe sizing

ModeRecommended size
Full chat (1, 2)min-width: 800px, min-height: 600px
Message panel (3)min-width: 400px, min-height: 500px

Security

  • Never pass the API token to the frontend. Authorization (/v1/embed/auth) must happen on your backend.
  • The session token is passed via the URL — the iframe clears it from the address bar immediately after loading.
  • The token in the iframe URL must not end up in your server logs or analytics: keep it only in page memory and issue a fresh one for each opening.
  • The session token has limited scope and an 8-hour lifetime.

Error handling

CodeCauseAction
401Invalid/expired API tokenCheck the API token in AISAR settings
400Missing required parameterCheck user_id in embed/auth
422User/contact not foundCheck the ID and its company membership

Limitations

  • One API token = one company. For several companies, use separate tokens.
  • contact_id belongs to the API token's company — contacts from other companies are not accessible.
  • The iframe works over HTTPS only (except localhost).
  • Max 20 results in /v1/contacts/lookup.