Перейти к содержимому
AISARAISAR
REST API

Команды и пользователи

Управление командами (группировка операторов + доступ к каналам), участниками компании и приглашениями новых пользователей по email. Группа также включает блок текущего пользователя (GET /me): профиль с ролями и правами в активной компании, статус доступности и переключение активной компании. GET /v1/users перечисляет реальных (не сервисных) пользователей компании. Отдельный блок — провижининг SIP-телефонии операторам (companies/current/members/telephony*, админский гейт company_telephony.manage) и самообслуживание оператора (/v1/softphone/*, только сессия/мобильный токен).

Роли и членство

Роль назначается на уровне компании (admin/manager/agent) через Spatie permissions с teams-режимом — один пользователь может состоять в нескольких компаниях с разными ролями.

Приглашения

Публичные шаги разрешения приглашения (resolve/context/intent, без auth) в этот справочник не включены — см. руководство по приглашениям.

Текущий пользователь

Блок текущего пользователя (GET /me) отдаёт профиль вместе с ролями и правами в активной компании — это отправная точка для потребителей сервисных токенов; сопутствующие эндпоинты обновляют профиль, статус доступности и активную компанию (при переключении компании профиль возвращает роли и права уже новой компании).

Статус доступности (PUT /v1/me/availability) принимает ровно три значения на запись: online, away, offline (busy — системное состояние, через этот эндпоинт не выставляется).

Активная компания

Активная компания хранится в едином серверном поле current_company_id вашего аккаунта: оно общее для всех ваших сессий и API-токенов (не привязано к отдельному токену), и по нему скоупятся company-ориентированные списки (например, GET /v1/conversations) и авторизация realtime-каналов.

Поэтому если тот же пользователь переключит компанию в другой вкладке, приложении или токене, за ним последуют все контексты — встроенный чат может внезапно показать диалоги другой компании, а подписка на каналы прежней (уже не активной) компании начнёт отвечать 403. Держите компанию, из которой читаете и на каналы которой подписаны, синхронной с current_company_id.

Настройки уведомлений

GET /v1/me/notification-preferences отдаёт снимок из четырёх блоков: channels — булевы мастер-переключатели по каналу доставки (mail, push, whatsapp; отсутствующий ключ трактуется как true), categories — объект по каждой категории уведомлений с полями enabled/label/controllable, а также push_triggers и quiet_hours (см. ниже). Категория transactional (коды подтверждения, приглашения, сброс пароля) всегда controllable: false и enabled: true — её нельзя отключить; остальные категории (onboarding, trial, billing, win_back, engagement) пользователь может выключать по отдельности.

PUT /v1/me/notification-preferences — частичное обновление (merge, не replace): передавайте только те ключи channels.*/categories.*/push_triggers.*/quiet_hours.*, которые меняете — остальные ключи, включая другие блоки целиком, сохраняют текущее значение. channels.whatsapp = false — единственный способ для пользователя отказаться от WhatsApp-канала биллинговых уведомлений (напоминания об оплате, приостановке и т.п.) — этот отказ обязателен политикой Meta для WhatsApp-шаблонов и должен уважаться отправителем.

Оба эндпоинта также несут push_triggers — объект булевых переключателей по типу push-уведомления: chat_message_new, conversation_assigned, call_missed, call_incoming, company_unassigned. По умолчанию включены все, кроме company_unassigned (пуш о том, что диалог в компании остался без ответственного — опционален, чтобы не заваливать им сразу всех операторов). call_incoming фактически всегда доставляется независимо от сохранённого значения — входящий звонок это системное уведомление, которое не подавляется.

quiet_hours — окно «не беспокоить»: { "enabled": bool, "start": "HH:MM"|null, "end": "HH:MM"|null }, по умолчанию enabled: false и start/endnull. Пока окно активно, некритичные push-уведомления (например, conversation_assigned) подавляются — кроме call_incoming, который тихие часы не затрагивают. Время трактуется в часовом поясе пользователя (users.timezone); если start больше end, окно считается ночным (переходит через полночь, например 22:0008:00).

Подтверждение номера телефона

Номер из профиля (users.phone) можно подтвердить кодом, который приходит в WhatsApp: POST /v1/me/phone/send-otp отправляет 6-значный код, POST /v1/me/phone/verify с телом {"code": "123456"} его проверяет. Подтверждённый номер отражается полем phone_verified в GET /v1/me и служит адресом для WhatsApp-дубликатов биллинговых уведомлений. Изменение номера через POST /v1/me сбрасывает подтверждение.

send-otp не принимает номер в теле запроса — код всегда уходит на сохранённый номер профиля, поэтому сначала сохраните номер, а затем запрашивайте код. Ответ 200 содержит маскированный phone и expires_in (секунды жизни кода, сейчас 600). Возможные ошибки: 422 — номер не задан либо не проходит проверку формата E.164; 429 — превышены лимиты отправки/проверки; 409 (только у verify) — номер изменился между отправкой и проверкой, запросите код заново; 502 — сообщение не удалось доставить; 503 — исчерпан суточный лимит отправки кодов на платформе.

Оба эндпоинта доступны только сессионной авторизации и мобильным токенам. Сервисные аккаунты, клиентские API-токены и токены встраивания получают 403 — подтверждение номера остаётся действием живого пользователя.

Телефония операторов

Провижининг SIP-телефонии оператору — шаг, следующий за подключением SIP-канала (см. руководство по подключению каналов, раздел «SIP-телефония (BYO-транк)»). Администратор компании (право company_telephony.manage) включает телефонию конкретному участнику через POST /v1/companies/current/members/{memberId}/telephony/enable, что провижинит СРАЗУ два SIP-профиля: браузерный agent-{id}-web (для встроенного WebRTC-софтфона в приложениях AISAR, пароль непрозрачный) и внешний agent-{id} (для настольных SIP-телефонов и приложений вроде Zoiper/MicroSIP/Linphone, пароль типизируемый). Отдельного тумблера для внешнего профиля нет — disable снимает оба профиля разом.

Административные эндпоинты (companies/current/members/telephony*) вызываются company api_token наравне с остальной группой — партнёрский сервис-аккаунт с ролью admin (которая безусловно несёт company_telephony.manage, см. ниже) может провижинить операторов программно. Самообслуживание (/v1/softphone/*) — обратная ситуация: эти эндпоинты требуют, чтобы вызывающий БЫЛ тем самым оператором (сессионная авторизация или мобильный токен — тот же паттерн, что у подтверждения номера телефона выше), поэтому company api_token / сервисный аккаунт получает здесь 403 — своего SIP-профиля у сервисного аккаунта никогда нет (провижининг участников сознательно фильтрует is_service_account = false). Партнёрам доступен также server-to-server способ включения телефонии операторам без пользовательской сессии — он описан в партнёрской интеграционной документации.

company_telephony.manage не тарифный гейт: с 13.08.2026 роль admin в ЛЮБОЙ компании безусловно несёт это право (бэкфилл-миграция закрыла разрыв для компаний, заведённых раньше). Тарифный гейт живёт отдельно — фича telephony плана нужна оператору, чтобы САМОМУ пользоваться звонками (TelephonyAccess::availableTo), но не нужна администратору, чтобы управлять операторами, схемами и каналами.

Обе точки получения кредов внешнего профиля — админская GET .../telephony/credentials и операторская GET /v1/softphone/external-credentials — используют один и тот же построитель (ExternalSipCredentialPresenter), поэтому форма ответа не может разойтись: sip_username, sip_password, host, tcp_port (5060), tls_port (5061), default_transport: "TCP", codecs: ["opus", "PCMU", "PCMA"], media_encryption, registered (жива ли SIP-регистрация прямо сейчас — best-effort проверка через ARA, при ошибке трактуется как false) и provisioning_uri — generic sip:-URI (sip:user:pass@host:port;transport=tcp) для импорта по QR в Zoiper / MicroSIP / Linphone / Grandstream Wave. Не подходит для 3CX — его приложение читает только собственный формат провижининг-QR, там поля вводятся вручную. Браузерный (agent-{id}-web) пароль непрозрачный: GET .../telephony/credentials (админ) его вообще не возвращает — эндпоинт трогает только внешний профиль; а вот POST .../telephony/reset-password (админ), наоборот, ЕГО возвращает — ответ несёт свежую пару sip_username/sip_password браузерного профиля (тот же принцип одноразового показа, что у создания API-токена), и заодно молча ротирует внешний профиль, не отдавая его новый пароль в этом же ответе — свой новый внешний пароль оператор увидит через собственный /softphone/external-credentials.

POST .../telephony/extension — внутренний номер оператора, 3–4 цифры (^\d{3,4}$), уникален в пределах компании; пустое значение снимает номер. Требует, чтобы телефония уже была включена — иначе 422.

Самообслуживание оператора (только сессия/мобильный токен): GET /v1/softphone/credentials — собственные браузерные креды (используются встроенным WebRTC-софтфоном напрямую, не для ручного ввода); POST /v1/softphone/reset-password — их ротация; GET /v1/softphone/external-credentials / POST /v1/softphone/external/reset-password — то же для внешнего профиля, включая provisioning_uri для QR; GET /v1/softphone/colleagues — телефонные коллеги по компании (директория набора) с extension и статусом доступности; POST /v1/softphone/internal-call — звонок коллеге по callee_user_id либо внутреннему номеру; POST /v1/softphone/external-call — исходящий звонок через SIP-транк компании на внешний номер, с опциональным contact_id (резолвится строго в рамках компании — чужой/несуществующий id это 422 без молчаливого фолбэка на резолв по номеру). external-call разделяет с POST /v1/calls/originate общий лимит call-originate — 20 запросов в минуту на пользователя; те же ограничения по sip_outbound_gated и по антизлоупотребительной проверке IP-режима, что и у /calls/originate, применяются и здесь (см. группу «Звонки»).

Эндпоинты

МетодПуть
GET/v1/teams

Список команд

POST/v1/teams

Создание команды

GET/v1/teams/{team}

Получение команды

PATCH/v1/teams/{team}

Обновление команды

DELETE/v1/teams/{team}

Удаление команды

GET/v1/companies/current/members

Список участников текущей компании

POST/v1/companies/current/members/{memberId}/role

Смена роли участника

POST/v1/companies/current/members/{memberId}/revoke

Отзыв членства участника

GET/v1/users

Список пользователей текущей компании (без сервисных аккаунтов)

POST/v1/invitations

Отправка приглашения (email + роль)

POST/v1/invitations/{guid}/accept

Принятие приглашения

POST/v1/invitations/{guid}/decline

Отклонение приглашения

POST/v1/invitations/{invitationId}/role

Смена роли в приглашении

POST/v1/invitations/{invitationId}/revoke

Отзыв приглашения

DELETE/v1/invitations/{invitationId}

Удаление приглашения

GET/v1/me

Текущий профиль пользователя (роли и права)

POST/v1/me

Обновление профиля

POST/v1/me/password

Смена пароля

PUT/v1/me/availability

Установить статус доступности (online, away, offline)

PUT/v1/me/current-company

Переключение активной компании (единое поле для всех сессий/токенов)

GET/v1/me/notification-preferences

Снимок настроек уведомлений: каналы (mail/push/whatsapp) + категории + push-триггеры (push_triggers) + тихие часы (quiet_hours)

PUT/v1/me/notification-preferences

Частичное обновление настроек (channels.mail/push/whatsapp, categories.*, push_triggers.*, quiet_hours)

POST/v1/me/phone/send-otp

Отправка кода подтверждения в WhatsApp на сохранённый номер профиля

POST/v1/me/phone/verify

Проверка кода и подтверждение номера профиля

GET/v1/companies/current/members/telephony

Список реальных участников компании с телефонным статусом (включена ли, extension, включён ли внешний профиль, зарегистрирован ли он прямо сейчас) — для админ-таблицы операторов.

POST/v1/companies/current/members/{memberId}/telephony/enable

Включить телефонию участнику: провижинит браузерный (agent-{id}-web) и внешний (agent-{id}) SIP-профили одновременно.

POST/v1/companies/current/members/{memberId}/telephony/disable

Отключить телефонию участнику: снимает оба SIP-профиля.

GET/v1/companies/current/members/{memberId}/telephony/credentials

Креды внешнего SIP-профиля участника для админа (без входа под ним) — host/порты/кодеки/provisioning_uri; браузерный пароль не отдаётся.

POST/v1/companies/current/members/{memberId}/telephony/reset-password

Ротация SIP-паролей участника: возвращает новый пароль браузерного профиля и заодно молча ротирует внешний.

POST/v1/companies/current/members/{memberId}/telephony/extension

Назначить/снять внутренний номер участника (3–4 цифры, уникален в компании); требует включённой телефонии.

GET/v1/softphone/credentials

Собственные креды браузерного SIP-профиля вызывающего оператора. Требует сессии/мобильного токена — company api_token получает 403.

POST/v1/softphone/reset-password

Ротация собственного браузерного SIP-пароля.

GET/v1/softphone/external-credentials

Собственные креды внешнего SIP-профиля (для настольного телефона/Zoiper/MicroSIP) с provisioning_uri для QR.

POST/v1/softphone/external/reset-password

Ротация собственного внешнего SIP-пароля; заодно ротирует и браузерный.

GET/v1/softphone/colleagues

Телефонные коллеги по компании (директория набора) с extension и статусом доступности.

POST/v1/softphone/internal-call

Внутренний звонок коллеге по callee_user_id или внутреннему номеру.

POST/v1/softphone/external-call

Исходящий звонок на внешний номер через SIP-транк компании; опциональный contact_id (строго company-scoped); лимит call-originate — 20/мин.

Примеры

Приглашение нового пользователя

Запрос

bash
curl -X POST https://api.aisar.app/v1/invitations \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "new.agent@example.com",
    "role": "agent"
  }'

Ответ

json
{
  "data": {
    "message": "Invitation sent.",
    "invitation": {
      "id": 77,
      "guid": "b6e2a4d0-1234-4a90-9e21-5d3f0c8a9b11",
      "invite_url": "https://my.aisar.app/invitation/b6e2a4d0-1234-4a90-9e21-5d3f0c8a9b11",
      "email": "new.agent@example.com",
      "role": "agent",
      "expires_at": "2026-03-22T10:00:00.000000Z"
    }
  }
}

Создание команды

Запрос

bash
curl -X POST https://api.aisar.app/v1/teams \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Support",
    "description": "Customer success team",
    "channel_access_mode": "custom",
    "channel_ids": [7, 9],
    "member_ids": [5, 6]
  }'

Ответ

json
{
  "data": {
    "message": "Team created.",
    "team": {
      "id": 3,
      "company_id": 1,
      "name": "Support",
      "description": "Customer success team",
      "channel_access": { "mode": "custom", "channel_ids": [7, 9] },
      "member_ids": [5, 6],
      "created_at": "2026-03-15T10:00:00.000000Z",
      "updated_at": "2026-03-15T10:00:00.000000Z"
    }
  }
}

Профиль и права текущего пользователя

Запрос

bash
curl https://api.aisar.app/v1/me \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Ответ

json
{
  "data": {
    "id": 12,
    "name": "Aisha",
    "lastname": "Nurlanova",
    "email": "aisha@example.com",
    "email_verified": true,
    "phone": "+77000000001",
    "phone_verified": true,
    "photo": null,
    "country_code": "KZ",
    "language": "ru",
    "timezone": "Asia/Almaty",
    "current_company_id": 3,
    "roles": ["admin"],
    "permissions": ["company.view", "conversation.view", "message.send"],
    "company": { "id": 3, "name": "Acme" },
    "memberships": [
      { "company_id": 3, "company_name": "Acme", "roles": ["admin"], "status": "active" }
    ],
    "pending_invitations": []
  }
}

Обновление профиля

Запрос

bash
curl -X POST https://api.aisar.app/v1/me \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Aisha",
    "lastname": "Nurlanova",
    "phone": "+77000000001",
    "country_code": "KZ",
    "language": "ru",
    "timezone": "Asia/Almaty"
  }'

Ответ

json
{
  "data": {
    "id": 12,
    "name": "Aisha",
    "lastname": "Nurlanova",
    "email": "aisha@example.com",
    "phone": "+77000000001",
    "country_code": "KZ",
    "language": "ru",
    "timezone": "Asia/Almaty",
    "current_company_id": 3
  }
}

Смена пароля

Запрос

bash
curl -X POST https://api.aisar.app/v1/me/password \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "current_password": "YOUR_CURRENT_PASSWORD",
    "password": "YOUR_NEW_PASSWORD",
    "password_confirmation": "YOUR_NEW_PASSWORD"
  }'

Ответ

json
{
  "data": {
    "message": "Password updated."
  }
}

Обновление статуса доступности

Запрос

bash
curl -X PUT https://api.aisar.app/v1/me/availability \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "availability": "away"
  }'

Ответ

json
{
  "status": "ok"
}

Переключение активной компании

Запрос

bash
curl -X PUT https://api.aisar.app/v1/me/current-company \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "company_id": 4
  }'

Ответ

json
{
  "data": {
    "id": 12,
    "current_company_id": 4,
    "roles": ["manager"],
    "permissions": ["company.view", "conversation.view"]
  }
}

Пользователи компании

Запрос

bash
curl https://api.aisar.app/v1/users \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Ответ

json
{
  "data": [
    {
      "id": 12,
      "name": "Aisha",
      "lastname": "Nurlanova",
      "email": "aisha@example.com",
      "availability": "online",
      "last_login_at": "2026-03-20T09:14:00.000000Z"
    },
    {
      "id": 13,
      "name": "Damir",
      "lastname": "Serik",
      "email": "damir@example.com",
      "availability": "away",
      "last_login_at": "2026-03-19T18:02:00.000000Z"
    }
  ]
}

Снимок настроек уведомлений

Запрос

bash
curl https://api.aisar.app/v1/me/notification-preferences \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Ответ

json
{
  "data": {
    "channels": {
      "mail": true,
      "push": true,
      "whatsapp": true
    },
    "categories": {
      "onboarding": { "enabled": true, "label": "Onboarding", "controllable": true },
      "trial": { "enabled": true, "label": "Trial", "controllable": true },
      "billing": { "enabled": true, "label": "Billing", "controllable": true },
      "win_back": { "enabled": true, "label": "Win-back", "controllable": true },
      "engagement": { "enabled": false, "label": "Engagement", "controllable": true },
      "transactional": { "enabled": true, "label": "Transactional", "controllable": false }
    },
    "push_triggers": {
      "chat_message_new": true,
      "conversation_assigned": true,
      "call_missed": true,
      "call_incoming": true,
      "company_unassigned": false
    },
    "quiet_hours": {
      "enabled": false,
      "start": null,
      "end": null
    }
  }
}

Отказ от WhatsApp-канала биллинговых уведомлений

Запрос

bash
curl -X PUT https://api.aisar.app/v1/me/notification-preferences \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "channels": {
      "whatsapp": false
    }
  }'

Ответ

json
{
  "data": {
    "channels": {
      "mail": true,
      "push": true,
      "whatsapp": false
    },
    "categories": {
      "onboarding": { "enabled": true, "label": "Onboarding", "controllable": true },
      "trial": { "enabled": true, "label": "Trial", "controllable": true },
      "billing": { "enabled": true, "label": "Billing", "controllable": true },
      "win_back": { "enabled": true, "label": "Win-back", "controllable": true },
      "engagement": { "enabled": false, "label": "Engagement", "controllable": true },
      "transactional": { "enabled": true, "label": "Transactional", "controllable": false }
    },
    "push_triggers": {
      "chat_message_new": true,
      "conversation_assigned": true,
      "call_missed": true,
      "call_incoming": true,
      "company_unassigned": false
    },
    "quiet_hours": {
      "enabled": false,
      "start": null,
      "end": null
    }
  }
}

Тихие часы и push о неразобранных диалогах

Запрос

bash
curl -X PUT https://api.aisar.app/v1/me/notification-preferences \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "push_triggers": {
      "company_unassigned": true
    },
    "quiet_hours": {
      "enabled": true,
      "start": "22:00",
      "end": "08:00"
    }
  }'

Ответ

json
{
  "data": {
    "channels": {
      "mail": true,
      "push": true,
      "whatsapp": true
    },
    "categories": {
      "onboarding": { "enabled": true, "label": "Onboarding", "controllable": true },
      "trial": { "enabled": true, "label": "Trial", "controllable": true },
      "billing": { "enabled": true, "label": "Billing", "controllable": true },
      "win_back": { "enabled": true, "label": "Win-back", "controllable": true },
      "engagement": { "enabled": false, "label": "Engagement", "controllable": true },
      "transactional": { "enabled": true, "label": "Transactional", "controllable": false }
    },
    "push_triggers": {
      "chat_message_new": true,
      "conversation_assigned": true,
      "call_missed": true,
      "call_incoming": true,
      "company_unassigned": true
    },
    "quiet_hours": {
      "enabled": true,
      "start": "22:00",
      "end": "08:00"
    }
  }
}

Список операторов компании

Запрос

bash
curl https://api.aisar.app/v1/companies/current/members/telephony \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Ответ

json
{
  "data": [
    {
      "user_id": 12,
      "name": "Aisha Nurlanova",
      "email": "aisha@example.com",
      "photo": null,
      "telephony_enabled": true,
      "extension": "101",
      "external_enabled": true,
      "external_registered": true
    },
    {
      "user_id": 13,
      "name": "Damir Serik",
      "email": "damir@example.com",
      "photo": null,
      "telephony_enabled": false,
      "extension": null,
      "external_enabled": false,
      "external_registered": false
    }
  ]
}

Включить телефонию участнику

Запрос

bash
curl -X POST https://api.aisar.app/v1/companies/current/members/13/telephony/enable \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Ответ

json
{
  "data": {
    "message": "Telephony enabled.",
    "telephony": {
      "user_id": 13,
      "sip_username": "agent-13-web",
      "status": "active"
    }
  }
}

SIP-креды участника (вид админа)

Запрос

bash
curl https://api.aisar.app/v1/companies/current/members/13/telephony/credentials \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Ответ

json
{
  "data": {
    "sip_username": "agent-13",
    "sip_password": "Qw7Lm2VtRk4x",
    "host": "sip.aisar.app",
    "tcp_port": 5060,
    "tls_port": 5061,
    "default_transport": "TCP",
    "codecs": ["opus", "PCMU", "PCMA"],
    "media_encryption": "SRTP/SDES (over TLS)",
    "registered": false,
    "provisioning_uri": "sip:agent-13:Qw7Lm2VtRk4x@sip.aisar.app:5060;transport=tcp"
  }
}