Работа с эндпоинтами Developer API: примеры, постраничный вывод, idempotency
Обновлено: 11 ноября 2026 · 8 мин чтения
Эндпоинт это один адрес и одна операция API: метод (GET чтение, POST создание, PATCH изменение, DELETE удаление) и путь. Все эндпоинты, их параметры и примеры ответов есть на developer.clomni.ai на странице «API reference». Рядом с каждым эндпоинтом указаны нужные scope, достаточно одного из них. Эндпоинт, которого нет в списке, закрыт для токенов разработчика и возвращает 403 endpoint_not_available. Какой эндпоинт и scope нужны для какой задачи, описано в статье «Какие scope нужны: scope и endpoint по Вашей задаче» и в статьях «Scope и endpoint: …».
Шаги
-
1
Как строится запрос
Адрес начинается с
https://api.clomni.ai/v1, токен передаётся в заголовкеAuthorization: Bearer <token>, тело в JSON (Content-Type: application/json). Номер workspace в адресе не пишется.idдиалога в API совпадает с номером, который виден в панели: «диалог 1042» означаетGET /conversations/1042.- Обычные эндпоинты возвращают время в секундах Unix, эндпоинты синхронизации в формате ISO 8601 (
2026-11-08T16:00:00Z). Часовой пояс UTC. - Телефон пишется в международном формате:
+994501234567.
-
2
Читайте диалоги и сообщения
GET /conversations(scopeconversations:read) возвращает диалоги страницами по 25. Параметры:status(open,resolved,pending,snoozed,all, по умолчаниюopen),assignee_type(me,unassigned,assigned,all),inbox_id,page.curl "https://api.clomni.ai/v1/conversations?status=open&page=1" \ -H "Authorization: Bearer $CLOMNI_TOKEN"
const res = await fetch("https://api.clomni.ai/v1/conversations?status=open&page=1", { headers: { Authorization: `Bearer ${process.env.CLOMNI_TOKEN}` }, }); const { data } = await res.json(); for (const c of data.payload) console.log(c.id, c.status, c.meta.sender.name);import os, requests res = requests.get("https://api.clomni.ai/v1/conversations", params={"status": "open", "page": 1}, headers={"Authorization": f"Bearer {os.environ['CLOMNI_TOKEN']}"}, timeout=10) for c in res.json()["data"]["payload"]: print(c["id"], c["status"], c["meta"]["sender"]["name"])Поле диалога
can_replyпоказывает, можно ли сейчас написать клиенту свободное сообщение. Сообщения:GET /conversations/{conversation_id}/messages(scopemessages:read) отдаёт последние 20 сообщений, для более старых?before=<самый маленький id>.message_type:0входящее,1исходящее,2системная запись,3шаблон.status:sent,delivered,read,failed. -
3
Отвечайте и управляйте диалогом
POST /conversations/{conversation_id}/messages, scopemessages:send:curl -X POST "https://api.clomni.ai/v1/conversations/1042/messages" \ -H "Authorization: Bearer $CLOMNI_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 6f1c2a9e-3b7d-4f0a-9c55-0e8b1d2a7f41" \ -d '{"content": "Здравствуйте, Ваш заказ доставят сегодня."}'Канал отправляет сообщение в фоне, поэтому
statusсначалаsent, а результат приходит позже вебхукомmessage.updated. Если отправить не удалось, причина находится вcontent_attributes.external_error. Для внутренней заметки, которую клиент не видит, передайте"private": true(scopenotes:write).- Закрыть, открыть:
POST /conversations/{conversation_id}/toggle_statusс{ "status": "resolved" }(scopeconversations:write). - Назначить:
POST /conversations/{conversation_id}/assignmentsс{ "assignee_id": 12 }или{ "team_id": 3 }(scopeconversations:assign). - Список операторов и команд:
GET /agents,GET /teams.
- Закрыть, открыть:
-
4
Создавайте и ищите контакты
POST /contacts(scopecontacts:write):curl -X POST "https://api.clomni.ai/v1/contacts" \ -H "Authorization: Bearer $CLOMNI_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "Лейла Гасанова", "phone_number": "+994501234567", "identifier": "crm-10045"}'identifierэто ID в Вашей системе, он уникален в пределах workspace.PATCH /contacts/{contact_id}меняет только те поля, которые Вы передали.GET /contacts/search?q=crm-10045ищет по имени, e-mail, телефону иidentifier. Второй контакт с тем же e-mail или телефоном возвращает 422: сначала ищите, потом обновляйте. Ключиcustom_attributesнужно заранее создать в workspace. -
5
Постраничный вывод: обычные списки
GET /conversations:page(с 1), страница по 25, ответdata.metaиdata.payload.GET /contacts:page, страница по 15, ответmeta.count,meta.current_page,payload.GET /conversations/{conversation_id}/messages:before=<message_id>, каждый раз 20 сообщений.
Эти списки нужны для показа на экране. Не перебирайте их, чтобы перенести данные целиком: если между страницами приходит новый диалог, порядок сдвигается, и объекты могут потеряться.
-
6
Синхронизация: перенос данных в Вашу базу
GET /sync/conversations(conversations:read),GET /sync/messages(messages:read),GET /sync/contacts(contacts:read). Параметры:updated_since(ISO 8601),after(next_cursorиз предыдущего ответа),limit(1-100, по умолчанию 50). Ответ:data,next_cursor,has_more.- Первая загрузка: начните без
updated_sinceи продолжайте сafter=next_cursor, пока не получитеhas_more: false. - Сохраните самое большое полученное значение
updated_at. - В следующий раз
updated_since= сохранённое время минус 2 минуты. - Записывайте объект по
id(upsert), дубликат отбрасывайте. - Новое получайте сразу вебхуком, а синхронизацию запускайте раз в 5-15 минут.
В объектах синхронизации
idдиалога это внутренний ID, номер из панели находится вnumber(в сообщенииconversation_number). Ссылки на файлы живут недолго. Синхронизация ограничена 60 запросами в минуту. Чтобы один раз перенести всю историю, лучше подходитPOST /exports(exports:run, 1 задача одновременно, 6 в день). - Первая загрузка: начните без
-
7
Защита от повторной отправки: Idempotency-Key
Когда обрывается связь, нельзя понять, дошёл ли POST. Для каждой новой операции создавайте новый UUID и передавайте его в заголовке
Idempotency-Key, при повторной попытке отправляйте тот же.- Работает во всех POST-запросах
/v1, кроме/oauth/*. Ключ длиной 1-255 символов, хранится 24 часа в пределах приложения и workspace. - Тот же ключ, то же тело: операция не повторяется, сохранённый ответ возвращается с
Idempotency-Replayed: true. - Тот же ключ, другое тело: 409
idempotency_key_reused. Первый запрос ещё выполняется: 409idempotency_key_in_progress. - Ответы 5xx не сохраняются, с тем же ключом можно повторить.
Кроме того, у сообщения есть
content_attributes.client_echo_id: запрос с тем же значением в том же диалоге в течение 24 часов не создаёт новое сообщение. - Работает во всех POST-запросах
-
8
Лента событий: GET /v1/events
Возвращает события последних 30 дней (такие же, как в вебхуке, с теми же
id) от старых к новым. Нужны scopeevents:readи scope чтения темы (messages:read,conversations:read,contacts:read), иначе список приходит пустым. Параметры:types(напримерmessage.created,contact.updated),after,limit(1-100). Если у Вашего сервера нет открытого адреса, читайте ленту каждую минуту, а если есть, забирайте отсюда то, что пропустил вебхук.