Lalexi
API

API

Диалоги, сообщения, контакты, каналы, подключение номеров и рассылки Lalexi из вашей CRM, сайта или учётной системы: адрес, личный токен, пространство, ошибки, страницы, лимиты и повторы без дублей.

API Lalexi даёт вашим системам — CRM, сайту, учётной системе — те же диалоги, сообщения, контакты и каналы, с которыми ваша команда работает в Lalexi. Через API можно подключать и отключать номера мессенджеров, загружать их историю, читать переписку и писать в неё, первым написать на новый номер, делать рассылки, вести контакты, менять статус, ответственного и метки диалога, смотреть расход сообщений и получать события вебхуками.

Каждый запрос выполняется от имени одного человека — владельца токена — и ровно с теми правами, которые у него есть в пространстве. Всё, что отправлено или изменено через API, записывается на него, как если бы он нажал кнопку в Lalexi сам.

Адрес

https://app.lalexi.com/v1

Все пути ниже — относительно этого адреса: GET /me — это GET https://app.lalexi.com/v1/me. Тела запросов и ответов — JSON (Content-Type: application/json); файлы отправляются как multipart/form-data.

Токен

API принимает личный токен доступа. Он есть у каждого участника пространства: Настройки профиля → Токен доступа. Передавайте его в заголовке Authorization:

curl https://app.lalexi.com/v1/me \
  -H "Authorization: Bearer <ваш токен>"
  • Права токена — это ваши права. Токен администратора видит всё пространство, токен оператора — только его каналы и диалоги. Отдельных «ключей для интеграции» с другими правами нет: заведите для интеграции отдельного участника с нужной ролью, если не хотите, чтобы действия шли от вашего имени.
  • Сброс токена в настройках профиля сразу отключает старый.
  • Нет токена, неизвестный токен или не личный — ответ 401 invalid_api_key.
  • Храните токен как пароль: только на сервере, никогда в коде страницы или мобильного приложения. API рассчитано на запросы сервер–сервер и не отвечает браузерным запросам с чужих сайтов (CORS). Единственное исключение — сам этот сайт документации, чтобы в Справочнике работала кнопка Send.

Попробовать в браузере

Каждая страница Справочника — это ещё и рабочая форма. Вставьте личный токен в поле Authorization, заполните параметры и нажмите Send: запрос уйдёт прямо из браузера, ответ появится на той же странице. Это быстрее, чем собирать curl руками, и сразу показывает настоящие поля настоящего ответа, а не только схему.

Два предупреждения, оба важные.

Запросы настоящие. Тестового режима у API нет: POST /dialogs правда напишет человеку в мессенджер, POST /channels/{id}/disconnect правда отключит номер, DELETE /webhooks/{id} правда удалит подписку. Щупать без последствий можно всё, что GET.

Токен остаётся в браузере. Страница запоминает его в хранилище браузера, чтобы не вставлять каждый раз, и отправляет только на app.lalexi.com — ни на сервер документации, ни куда-то ещё. На чужом или общем компьютере токен туда лучше не вставлять, а если вставили — очистите данные сайта в браузере.

Пространство

Если вы состоите в нескольких пространствах, укажите нужное в заголовке X-Workspace-Id каждого запроса. Номера ваших пространств и ваша роль в каждом — в ответе GET /me (этому запросу заголовок не нужен):

curl https://app.lalexi.com/v1/channels \
  -H "Authorization: Bearer <ваш токен>" \
  -H "X-Workspace-Id: 7"

С одним пространством заголовок можно не передавать.

СитуацияОтвет
Несколько пространств, заголовка нет400 workspace_required
Пространство не ваше404 workspace_not_found
Пространство приостановлено403 workspace_suspended
В пространстве выключен доступ по API403 api_disabled

Номера и время

id диалога — это номер из его адреса в Lalexi, по нему удобно ссылаться на диалог. У остальных объектов id — их собственный номер. Время — ISO 8601 в UTC: 2026-10-27T09:30:00Z.

Ошибки

Любая ошибка приходит в одном виде:

{
  "error": {
    "code": "validation_failed",
    "message": "The request is invalid.",
    "details": { "text": ["is required"] }
  }
}

Решения в коде принимайте по code — это закрытый список. message — пояснение для человека (на английском), его текст может меняться. details есть, только когда есть что добавить: какие поля не прошли проверку, id уже существующего контакта, цифры исчерпанного лимита.

codeHTTPЧто случилось
invalid_json400Тело запроса — не JSON.
workspace_required400Несколько пространств и нет X-Workspace-Id.
invalid_api_key401Токена нет, он неизвестен или не личный.
forbidden403Ваша роль этого не позволяет.
workspace_suspended403Пространство приостановлено.
api_disabled403Доступ по API в пространстве выключен.
not_found404Объекта нет или он вам не виден (ответ одинаковый); так же отвечает неизвестный путь.
workspace_not_found404Пространство не ваше.
contact_exists409Контакт с таким телефоном, e-mail или идентификатором уже есть — его id в details.id.
idempotency_in_progress409Запрос с этим Idempotency-Key ещё выполняется.
duplicate409Такой же новый диалог (канал, получатель, текст) уже начат меньше минуты назад.
message_limit_reached409Лимит сообщений пространства исчерпан — details.limit, details.used.
channel_disconnected409Канал сейчас не подключён.
validation_failed422Запрос неверен; details называет поля.
invalid_cursor422Курсор повреждён.
idempotency_key_reused422Этот Idempotency-Key уже использован с другим запросом.
identifier_read_only422Идентификатор контакта из мессенджера менять нельзя.
invalid_assignee422Этот человек не работает в канале диалога.
invalid_team422Такой команды в пространстве нет.
attachment_invalid422Файл слишком большой или его нельзя сохранить.
channel_reply_only422Канал может только отвечать тем, кто написал первым.
channel_cannot_start422Канал не умеет начинать диалог через API.
probe_not_supported422Проверка номера работает только в каналах мессенджеров.
template_not_found422Это не одобренный шаблон WhatsApp Business этого канала.
invalid_recipient422Получатель не подходит для канала.
recipient_rejected422Мессенджер отказал этому получателю.
send_rejected422Мессенджер отказался принять сообщение.
rate_limited429Превышен лимит запросов — подождите Retry-After секунд.
internal_error500Сбой на нашей стороне.
upstream_unavailable503Служба доставки сообщений не ответила; ничего не отправлено, можно повторить.

Постраничная выдача

Списки отвечают так: {"data": [...], "next_cursor": "..."}. Параметр limit — сколько элементов вернуть (от 1 до 100, по умолчанию 25). Чтобы получить следующую страницу, передайте next_cursor из ответа в параметре cursor; на последней странице next_cursor равен null. Курсор — непрозрачная строка: не собирайте и не меняйте его.

Короткие списки — каналы, операторы, команды, метки, поля, вебхуки — приходят целиком, с next_cursor: null.

Для синхронизации диалогов используйте GET /conversations?updated_since=…: с этим параметром диалоги идут от самого раннего изменения к позднему, и диалог, изменившийся во время обхода, не теряется, а уходит в конец. Запомните updated_at последнего полученного диалога и передайте его в updated_since в следующий раз.

Повтор без дублей

POST /conversations/{conversation_id}/messages и POST /dialogs принимают заголовок Idempotency-Key — любую строку до 255 символов, например UUID или номер записи в вашей системе:

curl https://app.lalexi.com/v1/conversations/1042/messages \
  -H "Authorization: Bearer <ваш токен>" \
  -H "Idempotency-Key: crm-order-1042-confirmation" \
  -H "Content-Type: application/json" \
  -d '{"text": "Ваш заказ отправлен."}'
  • Повтор с тем же ключом в течение 24 часов ничего не отправляет заново и возвращает первый ответ.
  • Пока первый запрос выполняется, повтор получает 409 idempotency_in_progress.
  • Тот же ключ с другим телом — 422 idempotency_key_reused.
  • Ключи свои у каждого человека, пространства и адреса.
  • Если первая попытка упала на нашей стороне (ответ 5xx), ключ освобождается и следующая попытка выполняется по-настоящему.

Так безопасно повторять запрос после обрыва связи или тайм-аута: сообщение не уйдёт дважды.

Лимиты запросов

Что считаетсяЛимит
Запросы с одного токена300 в минуту
POST /dialogs с одного токена20 в минуту
GET /dialogs/probe с одного токена30 в минуту
POST /webhooks/{id}/test с одного токена5 в минуту
POST /channels и POST /channels/{id}/reconnect с одного токена, вместе10 в минуту
Фоновая работа в мессенджере с одного токена, вместе: POST …/history-import, PUT …/chat-filter, POST …/chat-filter/allow, POST /broadcasts, POST /broadcasts/{id}/rephrase10 в минуту
Запросы с одного IP-адреса600 в минуту

Сверх лимита — ответ 429 rate_limited с заголовком Retry-After: через сколько секунд закончится текущая минута. Лимиты сообщений пространства — отдельная история: они те же, что в Lalexi, и видны в GET /usage (только администраторам, как страницы «Использование» и «Лимиты»).

Новый диалог

POST /dialogs пишет первым — то же, что кнопка «Новое сообщение». Он работает в каналах, у которых capabilities.can_start_dialog равно true: мессенджеры (по номеру телефона), e-mail (по адресу, с темой письма) и WhatsApp Business (по номеру, с одобренным шаблоном). Боты и площадки объявлений могут только отвечать — 422 channel_reply_only.

  • Правило 60 секунд. В каналах мессенджеров тот же текст на тот же номер из того же канала второй раз в течение минуты не уйдёт — ответ 409 duplicate. Это защита от двойного нажатия; для безопасных повторов используйте Idempotency-Key.
  • Ответ 202 со "status": "unknown" значит, что исход не успел вернуться: сообщение могло уйти. Не отправляйте его снова вслепую — сначала найдите диалог (GET /conversations?phone=…). Повтор с тем же Idempotency-Key вернёт тот же unknown и второй раз не отправит.
  • 503 upstream_unavailable — ничего не отправлено, повторять безопасно.
  • GET /dialogs/probe заранее проверяет, есть ли у номера аккаунт в мессенджере канала, ничего не отправляя.

Подключение номера

POST /channels с {"type": "whatsapp"} начинает подключение — то же, что плитка канала в Настройки → Каналы → Добавить. В ответе connect_url: страница Lalexi, где владелец номера сканирует QR-код, вводит код из мессенджера или вставляет токен бота. Откройте её в браузере — в новой вкладке или всплывающем окне. Ссылка живёт недолго: на каждую попытку берите новую.

Когда подключение закончено, канал появляется в GET /channels с connected_by — это вы — и приходит вебхук channel.created. Подключать номера может любой участник пространства, как и в Lalexi. Какие типы можно подключить сейчас и что каждый умеет — GET /channel-types.

  • Переподключение. Если у номера status стал reconnect_required или disconnected, POST /channels/{id}/reconnect даёт такую же страницу для того же аккаунта. Канал, его id и диалоги остаются; по завершении статус станет connected, придёт channel.status_changed.
  • Отключение. POST /channels/{id}/disconnect отвязывает аккаунт. Канал и переписка остаются со статусом disconnected. Отключённый номер можно спрятать вместе с его диалогами — PATCH /channels/{id} с {"hidden": true}; в списке его видно с include_hidden=true.
  • Подпись. PATCH /channels/{id} с {"note": "Отдел продаж"} — подпись номера для команды.
  • Лимит подключений. Когда все подключения тарифа заняты, ответ 409 connection_limit_reached с details.limit и details.used.

Администратор управляет любым номером, оператор — своими (теми, в которых работает).

История и фильтр чатов

Новый номер принимает все свои чаты с момента подключения. Чтобы получить и прошлую переписку, запустите POST /channels/{channel_id}/history-import; GET по тому же адресу показывает, сколько уже загружено. Повторный запуск добавляет только недостающее.

Какие чаты номера попадают в пространство, решает фильтр: PUT /channels/{channel_id}/chat-filter с mode — all (все), include (только chat_ids) или exclude (все, кроме chat_ids). Id чатов берите из GET /channels/{channel_id}/chats: список загружается в фоне, пока status равен loading, повторите запрос через секунду-две. После сохранения фильтра история разрешённых чатов загружается сама. POST /channels/{channel_id}/chat-filter/allow пропускает ещё один чат — по номеру или id — не трогая остальные.

У ботов нет списка чатов и истории: там эти адреса отвечают 422 not_supported (смотрите capabilities.chat_list канала).

Рассылки

POST /broadcasts создаёт рассылку — черновик: ничего не уходит, пока вы не вызовете POST /broadcasts/{id}/schedule. Каждая строка items уходит со своего номера (channel_id) по очереди, с паузой delay_seconds (30–300 секунд) и не раньше scheduled_at. Номер должен быть вашим и уметь писать первым (capabilities.broadcasts).

Строки, которые отправить нельзя — чужой номер, номер бота, неверный телефон, пустой текст, — в рассылку не попадают и перечислены в errors с их позицией (index). Если не годится ни одна, рассылка не создаётся — 422 invalid_items.

Дальше: GET /broadcasts/{broadcast_id}/items — получатели и их статусы, PATCH /broadcasts/{broadcast_id}/items/{id} — другой текст или время для одного получателя, POST /broadcasts/{id}/rephrase — варианты текста от ИИ по промпту пространства (/broadcasts/rephrase-prompt), POST /broadcasts/{id}/cancel и DELETE /broadcasts/{id}. Рассылки пространства видны всем его участникам, как в Lalexi. Менять рассылку — запускать, отменять, удалять, править получателей — может администратор, а остальные только когда затронутые строки уходят с их собственных номеров (иначе 403 forbidden).

Свои сообщения

Всё, что написано через API — POST /conversations/{conversation_id}/messages и POST /dialogs, — помечено "via": "api" в ответах и в вебхуках. Передайте свой external_id (до 255 символов), и он вернётся на том же сообщении. Так интеграция отличает свои сообщения от написанных в Lalexi, с телефона или контактом и не заносит их к себе второй раз.

Совместимость

Внутри v1 изменения только добавляются: новые адреса, новые необязательные поля запросов, новые поля ответов, новые события вебхуков, новые коды ошибок, новые значения открытых списков (типы каналов, типы вложений). Удаление и переименование полей или смена их типа — только в новой версии, /v2.

Поэтому ваша интеграция должна пропускать незнакомые поля и значения, а неизвестный код ошибки обрабатывать по HTTP-статусу.

Спецификация

Весь API описан одним файлом OpenAPI 3.1 — его можно скачать:

https://docs.lalexi.com/openapi/public-api.yaml

Это тот же документ, из которого собран Справочник, так что они не могут разойтись. Файл подходит, чтобы сгенерировать клиент на своём языке, загрузить схему в Postman или Insomnia, или отдать её ИИ-агенту — тогда он будет собирать запросы по описанию, а не по догадкам.

Тот же файл открыт в Swagger UI — одна страница со всеми адресами сразу, привычная всем, кто работал с другими API. Там же можно отправить запрос: нажмите «Authorize», вставьте токен, раскройте адрес и «Try it out».

Генерация клиента, например:

npx @openapitools/openapi-generator-cli generate \
  -i https://docs.lalexi.com/openapi/public-api.yaml \
  -g typescript-fetch -o ./lalexi-client

Дальше

Содержание