Серверное API
Эта страница — для того, кто подключает Globask со стороны своего сервера. Она же контракт: всё, что здесь описано, менять без предупреждения нельзя.
Способов ходить друг к другу три, и они независимы:
| Часть | Кто кого зовёт | Зачем |
|---|---|---|
| Чтение | вы — нас | выгрузка переписки, архив в карточке CRM |
| Отправка | вы — нас | сообщение посетителю из вашей системы |
| Вебхуки | мы — вас | события ваших диалогов в реальном времени |
Чтение и отправка требуют ключа, вебхуки — нет: они настраиваются в кабинете и подписываются секретом.
Ключи
Ключ выпускается в кабинете: проект → вкладка «Ключи API». Ключ принадлежит проекту, а не аккаунту: утёкший ключ уносит переписку одного сайта, а не всех сразу. У проекта их может быть несколько — по одному на интеграцию.
У ключа две способности, и выдавать их лучше по отдельности:
| Способность | Что открывает |
|---|---|
| «Чтение» | все GET-запросы ниже |
| «Отправка» | POST сообщения в диалог |
Ключ показывается один раз — сразу после выпуска. Повторно мы его не
покажем: в базе хранится не он, а его sha256, и показывать нам просто
нечего. Потеряли — отзовите и выпустите новый.
Передаётся он заголовком, и только им:
Authorization: Bearer gsk_ваш_ключ
В адресе ключ не принимается намеренно: адреса оседают в логах прокси, в истории браузера и в чужих системах мониторинга — вместе с ключом.
Все адреса начинаются с https://globask.com/api/v1/. Версия в пути стоит с
первого дня: на вашей стороне живёт код, который мы не сможем переписать по
своей воле.
Проверить ключ:
curl -H "Authorization: Bearer gsk_…" https://globask.com/api/v1/project
{
"project": {
"public_key": "pk_…",
"name": "Мой сайт",
"timezone": "Europe/Moscow"
},
"token": {
"name": "Выгрузка в BI",
"abilities": ["read"],
"expires_at": null
}
}
Ошибки
Коды обычные, тело — {"message": "…"}, у ошибок проверки полей ещё и
errors.
| Код | Когда |
|---|---|
| 400 | тело запроса не разобралось как JSON: оборванный синтаксис или не UTF-8 |
| 401 | ключа нет, он неизвестен, отозван или просрочен |
| 403 | ключу не хватает способности; аккаунт приостановлен |
| 404 | записи нет или она из другого проекта — мы не различаем эти случаи вслух |
| 422 | параметр не подходит: неизвестный статус, чужой курсор, пустой текст |
| 429 | превышен лимит: 120 запросов в минуту на чтение, 60 на отправку |
Про 400 стоит знать заранее. Тело мы разбираем сами и на битом отвечаем прямо: «не разобрано как JSON». Раньше такой запрос получал 422 «Поле body обязательно» — формально верно (полей и правда нет) и практически вредно: ответ отправляет искать ошибку в коде отправки, а не в кодировке. Самая частая причина — не UTF-8: тело собрано в CP1251 или уехало через слой, который его перекодировал.
Чтение
Как листать
Списки отдаются от старых записей к новым и листаются курсором:
GET /api/v1/conversations?limit=50&after=<id последней прочитанной записи>
limit— по умолчанию 50, потолок 100;next_afterв ответе — то, что нужно передать вafterза следующей страницей;nullозначает, что страница последняя;afterс неизвестным идентификатором — ошибка 422, а не «начни сначала»: иначе опечатка превратила бы ваш цикл в бесконечную выгрузку одного и того же.
Смещений (page, offset) у нас нет намеренно: пока вы листаете, приходят
новые сообщения, страницы съезжают, и записи начинают дублироваться или
теряться молча.
Порядок «от старых к новым» не меняется никогда. Если вам нужны свежие события первыми — вам нужны не списки, а вебхуки.
Диалоги
GET /api/v1/conversations
GET /api/v1/conversations/{id}
Фильтры: status (open, pending, closed), contact (идентификатор
контакта).
{
"conversations": [
{
"id": "0198f3bf-…",
"status": "open",
"created_at": "2026-08-25T10:15:30+03:00",
"last_message_at": "2026-08-25T10:19:02+03:00",
"contact": {
"id": "0198f3be-…",
"number": 5,
"name": null,
"email": null
}
}
],
"next_after": null
}
Сообщения диалога
GET /api/v1/conversations/{id}/messages
{
"messages": [
{
"id": "0198f3c0-…",
"direction": "in",
"body": "Сколько стоит доставка?",
"author": { "type": "contact", "via": null, "name": null },
"content_type": "text",
"attachments": [],
"created_at": "2026-08-25T10:15:30+03:00"
}
],
"next_after": null
}
direction — in от посетителя, out к посетителю. author.type — contact,
user (менеджер), unlinked_agent, bot (автоответ или ваша собственная
отправка) и system.
author.via отвечает на вопрос «это не я ли сам?». У bot два разных
источника: via: "api" — сообщение, которое отправили вы через это же API,
via: null — наш автоответ. Различать их нужно всерьёз: если вы подписаны на
message.created.out, ваша собственная отправка вернётся к вам событием, и
без via вы запишете своё же сообщение вторым. У остальных типов автора
via всегда null.
system — это внутренние заметки менеджеров. Посетитель их не видит, а вы
видите: это ваши данные, и архив, умалчивающий половину разговора, врал бы о
его содержании. Если вам нужна только переписка с посетителем — отбросьте
system у себя.
Контакты
GET /api/v1/contacts
GET /api/v1/contacts/{id}
Один контакт приходит вместе с идентичностями — способами, которыми человек с вами связывался:
{
"contact": {
"id": "0198f3be-…",
"number": 5,
"name": null,
"email": null,
"blocked": false,
"created_at": "2026-08-25T10:10:00+03:00",
"identities": [
{
"channel": "widget",
"external_id": "v_…",
"page_url": "https://shop.example/cart",
"created_at": "2026-08-25T10:10:00+03:00"
}
]
}
}
Вложения
Ссылка приходит в сообщении: attachments[].url. Она не работает сама по
себе — требует того же заголовка Authorization, что и всё остальное.
Подписанных ссылок, живущих без ключа, у нас нет: они утекают из чужих логов и
работают у всякого, кто их подобрал.
Отправка
POST /api/v1/conversations/{id}/messages
Content-Type: application/json
{ "body": "Заказ №1024 отправлен, трек 12345.", "client_message_id": "…uuid…" }
Ответ — то же сообщение, что отдаёт чтение, плюс текущее состояние диалога. Код 201 на новое сообщение и 200 на повтор.
Что нужно знать до первой отправки:
- Сообщение помечено автоматическим. В ленте виджета оно выглядит как ответ робота, а не оператора. Выдавать вашу систему за живого человека мы не станем: тот, кто ждёт продолжения разговора, не дождётся.
client_message_id— ваш ключ идемпотентности. Он необязателен, но без него сетевой таймаут на вашей стороне обернётся вторым «заказ отправлен» у посетителя. Повтор с тем же ключом возвращает то же самое сообщение.- Закрытый диалог оживает. Уведомление приходит как раз тогда, когда разговор давно закончен, — отказ был бы отказом в главном сценарии. Вместе с диалогом откроется и тема, в которой отвечают менеджеры.
- Диалог не перестаёт считаться ждущим. Ваше сообщение отвечает на свой
повод, а не на вопрос посетителя, поэтому
last_message_atи статус открытого диалога не меняются. Иначе отправка «заказ собран» прятала бы от менеджера человека, который третий час ждёт ответа. - Менеджер видит, что вы ответили. В тему Telegram уходит строка «через API» с текстом сообщения — иначе он не поймёт, почему посетителю уже ответили, и ответит второй раз.
Завести новый диалог через API нельзя: сообщение уходит в существующий, а диалог заводит посетитель. Вложения через API пока не отправляются.