API
Как управлять кабинетом KELVIN TG из своей программы — ключ, запросы и примеры на каждое действие.
API — это способ делать из своей программы то же, что ты делаешь в кабинете руками: читать цифры и ответы лидов, создавать и запускать рассылки, отвечать в чатах. Ничего сверх кабинета API не умеет, и все защиты аккаунтов работают так же.
API включается для кабинета отдельно. Если в меню кабинета нет раздела «API», напиши в поддержку — включим.
Получи ключ
- Открой в кабинете «API» и нажми «Создать ключ».
- Впиши название — по нему ты потом поймёшь, где ключ используется.
- Выбери право ключа и нажми «Создать ключ».
- Скопируй ключ. Он показывается один раз: закрыл окно, не сохранив, — отзови ключ и создай новый.
| Право ключа | Что может программа |
|---|---|
| «Только чтение» | Видит рассылки, статистику, аккаунты и чаты. Ничего не меняет и не отправляет. |
| «Чтение и действия» | Плюс создаёт и запускает рассылки, отвечает лидам, меняет настройки. |
| Галочка «Разрешить опасные действия» | Плюс удаляет аккаунты и телефоны, выгружает весь кабинет, снимает блок @SpamBot. Не ставь без нужды. |
В кабинете может быть до пяти ключей. Ключ — это пароль: не отправляй его в чаты и не вставляй на сайты. Если ключ мог попасть к чужим, отзови его в разделе «API» — он перестанет работать сразу.
Первый запрос
Вставь свой ключ вместо kelvin_… и выполни в терминале:
export KELVIN_KEY="kelvin_…"
curl "https://app.kelvintg.ru/api/v1/me" \
-H "Authorization: Bearer $KELVIN_KEY"В ответе — название кабинета и право ключа. Значит, всё подключено.
Как устроены запросы
- Адрес. Все запросы начинаются с
https://app.kelvintg.ru/api/v1. - Ключ. В каждом запросе — заголовок
Authorization: Bearerи твой ключ. - Данные. Тело запроса и ответ — JSON.
- Лимит. Один ключ принимает до 120 запросов в минуту. Сверх лимита придёт отказ
rate_limitedи число секунд, через которое можно повторить. На скорость рассылок лимит не влияет. Статистику и выгрузку кабинета можно запрашивать до 10 раз в минуту: они считаются по всем отправкам. - Отправляют телефоны. Ответ «принято» значит, что сообщение встало в очередь телефона. Телефон отправит его в своём темпе и в пределах дневного лимита аккаунта. Итог смотри в состоянии рассылки или диалога.
Состояния
Ответ «принято» — это ещё не «отправлено». Что происходит дальше, видно по состоянию.
| Что | Состояние | Что значит |
|---|---|---|
| Рассылка | pending | Черновик: создана, не запущена. |
running | Идёт: телефоны берут сообщения по очереди. | |
paused | На паузе. | |
cancelled | Отменена, вернуть нельзя. | |
completed | Все сообщения отправлены. | |
completed_with_issues | Закончена, но часть сообщений не ушла. | |
| Сообщение и ответ лиду | pending | В очереди телефона. |
claimed, authorized | Телефон взял сообщение и отправляет. | |
sent | Отправлено. | |
failed | Не отправлено, причина — в reason. | |
unknown, needs_review | Телефон не увидел подтверждения. Не отправляй заново: KELVIN проверит сам. | |
cancelled | Отменено до отправки. | |
| Телефон | ready | На связи и готов работать. |
unhealthy | На связи, но что-то мешает: экран заблокирован, нет сети или выключены «Действия». | |
offline | Не выходил на связь. |
Аккаунт работает, если у него enabled: true, нет deletedAt и blockedReason, а его телефон в состоянии ready.
Повтор запроса
Связь может оборваться, и ты не узнаешь, дошёл ли запрос. Чтобы повтор не создал вторую рассылку и не отправил ответ дважды, передавай в создающих запросах заголовок Idempotency-Key — свой номер этого запроса, от 8 до 64 символов.
- Повтор с тем же номером ничего не делает второй раз и возвращает тот же ответ.
- Ответы хранятся неделю. Этого хватает, чтобы повторить запрос после обрыва связи.
- Один номер — один запрос. Для нового действия бери новый номер.
- Если первый запрос оборвался на середине, придёт отказ
request_in_progress. Проверь результат чтением и только потом решай, отправлять ли заново с новым номером.
В описании каждого запроса сказано, нужен ли ему номер.
Отказы
Отказ приходит с кодом для программы и фразой для человека:
{ "error": { "code": "read_only_key", "message": "Этот ключ только для чтения. Создай в кабинете ключ с правом «чтение и действия»." } }| Код | Что случилось | Что сделать |
|---|---|---|
invalid_key | Ключ не подошёл или отозван. | Проверь заголовок или создай новый ключ. |
api_disabled | API для кабинета выключен. | Напиши в поддержку. |
access_ended | Доступ к кабинету закончился или приостановлен. | Продли доступ — ключ заработает снова. |
read_only_key | Ключ только для чтения, а запрос что-то меняет. | Создай ключ с правом «Чтение и действия». |
danger_not_allowed | Действие опасное, а у ключа нет этой галочки. | Создай ключ с галочкой «Разрешить опасные действия». |
rate_limited | Больше 120 запросов в минуту. | Повтори через число секунд из ответа. |
idempotency_key_required | Запросу нужен номер, а его нет. | Добавь заголовок Idempotency-Key. |
request_in_progress | Первый запрос с этим номером не закончился. | Проверь результат чтением. |
idempotency_key_reused | Этот номер уже был у другого запроса или с другими данными. | Возьми новый номер. |
answer_not_kept | Запрос уже выполнен, но ответ был слишком большой и не сохранён. | Проверь результат чтением, повторять не нужно. |
not_found | Такого адреса или объекта в твоём кабинете нет. | Проверь адрес и номер объекта. |
У отказов кабинета коды свои, например campaign_not_found или template_empty. Если сервер знает подробности — какое поле, какой аккаунт, какое место в тексте, — они придут рядом в details.
Частые задачи
Отправить одно сообщение одному человеку
Отдельного запроса нет: это рассылка из одного получателя. Сначала создай её, потом запусти.
curl -X POST "https://app.kelvintg.ru/api/v1/campaigns" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Idempotency-Key: order-0001" \
-H "Content-Type: application/json" \
-d '{"name": "Заявка 0001", "recipientsText": "synthetic_lead", "template": "Здравствуйте! Это проверка.", "accountIds": ["ID_АККАУНТА"]}'
curl -X POST "https://app.kelvintg.ru/api/v1/campaigns/ID_РАССЫЛКИ/start" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" -d '{}'ID_АККАУНТА возьми из списка аккаунтов, ID_РАССЫЛКИ — из ответа первого запроса. Повторный запуск уже идущей рассылки безопасен: второй раз ничего не отправится. Человеку, который уже тебе ответил, проще написать через ответ в чате.
Забирать ответы лидов
Запрашивай новые сообщения «после какого»: в первый раз с after=0, дальше — с числом after из прошлого ответа. Так ничего не потеряется и не придёт дважды.
curl "https://app.kelvintg.ru/api/v1/chats/incoming?after=0" \
-H "Authorization: Bearer $KELVIN_KEY"after — это номер последнего сообщения, которое ты уже получил. Если новых нет, after в ответе не меняется. Раз в 5–10 секунд достаточно. Если в ответе more: true, запроси ещё раз сразу — пришло больше, чем помещается в один ответ.
Ответить лиду
curl -X POST "https://app.kelvintg.ru/api/v1/chats/ID_ДИАЛОГА/reply" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Idempotency-Key: reply-0001" \
-H "Content-Type: application/json" \
-d '{"text": "Спасибо за ответ! Расскажу подробнее."}'ID_ДИАЛОГА — это chatId из входящего сообщения. Ответ уходит с того же аккаунта, которому писал лид. Запомни свой номер из Idempotency-Key: по нему запрос «Дошёл ли ответ» скажет, что стало с ответом.
Остановить всё
Программа может нажать «Остановить всё» — например, если твоя система заметила проблему. Возобновить работу может только человек в кабинете.
curl -X POST "https://app.kelvintg.ru/api/v1/work/stop-all" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" -d '{}'Для ИИ-помощника
Полное машинное описание всех запросов лежит по адресу /api/v1/openapi.json. Отдай эту ссылку своему ИИ-помощнику или программисту — по ней видно каждый запрос, его поля и право ключа.
Чего в API нет
- Оплаты и подписки, смены пароля и логина.
- Кодов подключения телефонов и всего, что телефон делает сам.
- Ключа ИИ и настройки раздела «ИИ».
- Кнопки «Возобновить работу»: это решение человека.
- Смены аватарки аккаунта и добавления получателей в уже запущенную рассылку — этого нет и в кабинете. Чтобы написать новым людям, создай новую рассылку.
Все запросы
Ниже — каждый запрос: что он делает, пример и ответ. В примерах $KELVIN_KEY — твой ключ, слова вроде ID_РАССЫЛКИ замени на номер из ответа предыдущего запроса.
Проверка ключа
Проверить ключ
GET /me · право ключа: только чтение
Отвечает, к какому кабинету относится ключ, что ему разрешено и до какого числа открыт доступ. С этого запроса удобно начать: если он ответил, ключ вставлен правильно.
curl "https://app.kelvintg.ru/api/v1/me" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"workspace": {
"id": "ID",
"name": "Демо-кабинет",
"accessUntil": null
},
"key": {
"id": "ID",
"name": "Пример",
"scope": "danger"
},
"limitPerMinute": 120
}Рассылки
Список рассылок
GET /campaigns · право ключа: только чтение
Отдаёт все рассылки кабинета, новые сверху, и отдельно те, что лежат в корзине. Получателей в этом списке нет: они приходят в запросе одной рассылки.
curl "https://app.kelvintg.ru/api/v1/campaigns" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"campaigns": [],
"deletedCampaigns": []
}Рассылка и её получатели
GET /campaigns/ID_РАССЫЛКИ · право ключа: только чтение
Отдаёт рассылку целиком: настройки, статус и что стало с каждым получателем. Здесь же лежит номер версии revision, он нужен, чтобы менять рассылку. Рассылку из корзины этот запрос не находит.
curl "https://app.kelvintg.ru/api/v1/campaigns/ID_РАССЫЛКИ" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"id": "ID",
"name": "Проверка",
"baseLabel": null,
"status": "pending",
"createdAt": "2026-10-10T10:00:00.000Z",
"schedule": null,
"scheduleStatus": null,
"editable": true,
"revision": 1,
"startedAt": null,
"secondTouch": {
"enabled": false,
"waiting": false,
"planned": 0,
"sent": 0
},
"post": null,
"autoReply": {
"enabled": false,
"sent": 0,
"waiting": 0,
"refused": 0,
"missed": 0
},
"total": 1
}Скачать получателей таблицей
GET /campaigns/ID_РАССЫЛКИ/export · право ключа: только чтение
Отдаёт получателей рассылки файлом CSV с их статусами, как кнопка выгрузки в кабинете. Ответ — файл, а не JSON: разделитель «;», открывается в Excel.
| Поле | Где | Что это |
|---|---|---|
filter | в адресе | строка. Кого выгрузить: all — всех (по умолчанию), waiting — кто ещё в очереди, review — с ошибками, unknown — где отправка ещё проверяется, либо точный статус: pending, claimed, authorized, sent, failed, needs_review, cancelled. |
q | в адресе | строка. Поиск по получателю (без @) и по значениям полей из таблицы. |
curl "https://app.kelvintg.ru/api/v1/campaigns/ID_РАССЫЛКИ/export?filter=sent" \
-H "Authorization: Bearer $KELVIN_KEY"Проверить список получателей
POST /import/preview · право ключа: только чтение
Разбирает список и показывает, кого KELVIN распознал, какие строки не подошли, сколько повторов и кого уберёт «Не писать». Ничего не сохраняет. Удобно вызвать перед созданием рассылки.
| Поле | Где | Что это |
|---|---|---|
text — обязательно | в теле | строка. Получатели, по одному в строке: username или телефон, как в рассылке. Не больше 20 000. |
curl -X POST "https://app.kelvintg.ru/api/v1/import/preview" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "@synthetic_lead\nsynthetic_lead_two"
}'Ответ:
{
"recipients": [
{
"kind": "username",
"value": "synthetic_lead"
},
"… ещё 1"
],
"invalid": [],
"duplicates": 0,
"excluded": []
}Проверить текст сообщения
POST /messages/preview · право ключа: только чтение
Показывает, какие сообщения получатся из текста с вариантами и полями. Если передать получателей, покажет ещё, у кого не хватает значений и как распозналось имя. Ничего не сохраняет.
| Поле | Где | Что это |
|---|---|---|
template — обязательно | в теле | строка. Текст с вариантами {а|б} и полями [[поле|запасной текст]]. Вложенные скобки не поддерживаются. |
recipientsText | в теле | строка. Получатели, как в рассылке. Без них в ответе будут только варианты текста и их число. |
recipientFields | в теле | объект. Поля из таблицы по получателям, как в рассылке. |
nameExclusions | в теле | список строк. Кому писать без обращения по имени, как в рассылке. |
filter | в теле | строка. Кого показать в таблице имён: "all" (по умолчанию), "recognized" — имя распознано, "unrecognized" — не распознано. |
offset | в теле | число. С какой строки таблицы имён начать, от 0. По умолчанию 0. |
limit | в теле | число. Сколько строк таблицы имён отдать, 1–200. По умолчанию 20. |
curl -X POST "https://app.kelvintg.ru/api/v1/messages/preview" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": "{Здравствуйте|Добрый день}! Это проверка."
}'Ответ:
{
"variants": [
"Здравствуйте! Это проверка.",
"… ещё 1"
],
"count": 2
}| Отказ | Что случилось и что сделать |
|---|---|
| 400 | В тексте ошибка в фигурных скобках: лишняя, незакрытая, вложенная или с пустым вариантом. В ответе указано место. |
Проверить пост
POST /posts/check · право ключа: чтение и действия
Проверяет пост, который ты хочешь разослать вместо текста: код от @PostBot или ссылку на пост публичного канала. Ничего не сохраняет. Для кода проверяется только его вид, для ссылки KELVIN открывает пост на t.me.
| Поле | Где | Что это |
|---|---|---|
post — обязательно | в теле | объект. Пост от @PostBot: {via: "postbot", codes: ["код", …]}, код — 6–64 латинских букв, цифр, «_» и «-». Пост из канала: {via: "forward", links: ["t.me/канал/123", …]}, только публичные каналы. В обоих случаях не больше 50 постов. |
curl -X POST "https://app.kelvintg.ru/api/v1/posts/check" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"post": {
"via": "postbot",
"codes": [
"synthetic0code1"
]
}
}'Ответ:
{
"ok": true,
"post": {
"via": "postbot",
"codes": [
"synthetic0code1"
]
},
"line": "Пост · @PostBot synthetic0code1"
}| Отказ | Что случилось и что сделать |
|---|---|
| 400 | Пост не открывается: канал должен быть публичным, а пост существовать. Ссылки вида t.me/c/… на закрытый канал не подходят. |
| 400 | Сайт t.me не ответил, пост проверить не удалось. Повтори через минуту. |
Проверить рассылку без создания
POST /campaigns/rehearsal · право ключа: только чтение
Принимает те же поля, что «Создать рассылку», и делает те же проверки, но ничего не сохраняет. В ответе: сколько получателей останется после «Не писать», сколько вариантов текста и до пяти примеров готовых сообщений.
| Поле | Где | Что это |
|---|---|---|
name — обязательно | в теле | строка. Название рассылки, до 200 знаков. |
template — обязательно | в теле | строка. Текст сообщения, до 20 000 знаков со всеми вариантами. Варианты пишутся как {Здравствуйте|Добрый день}, поля из таблицы как [[город|запасной текст]], обращение по имени как [[имя]]. Каждый итоговый вариант не длиннее 4096 знаков. Можно не передавать, только если отправляешь пост без текста. |
recipientsText — обязательно | в теле | строка. Получатели, по одному в строке: username (5–32 знака, с @ или без, можно ссылкой t.me/имя) или телефон (8–15 цифр). Не больше 20 000. Повторы убираются сами, любая нераспознанная строка даёт отказ. |
accountIds — обязательно | в теле | список строк. С каких аккаунтов отправлять: хотя бы один аккаунт этого кабинета. Получатели раздаются по аккаунтам по кругу. |
schedule | в теле | объект. Когда можно отправлять: {timeZone: "Europe/Moscow" или "UTC", startLocal: "ГГГГ-ММ-ДДTЧЧ:ММ" (не раньше текущей минуты) или null, weekdays: дни недели 0–6, где 0 — воскресенье, intervals: от 1 до 4 отрезков {start: "ЧЧ:ММ", end: "ЧЧ:ММ"}}. Если конец раньше начала, отрезок переходит через полночь. Без поля рассылка идёт без расписания. |
pacing | в теле | объект. Темп. Любое поле можно не передавать, тогда берётся значение из скобок: batchMin и batchMax — сообщений подряд, 1–20 (2 и 5); waitMinSeconds и waitMaxSeconds — пауза между сообщениями, 10–1800 с (55 и 85); readMinSeconds и readMaxSeconds — перерыв между сериями, 30–600 с (90 и 240); readInBreaks — читать каналы в перерывах (да); spreadEnabled — растягивать отправку по времени (да); spreadMinutes — 15–480 (60). Минимум не больше максимума. |
recipientFields | в теле | объект. Поля из таблицы по получателям: {"username:synthetic_lead": {"город": "Казань"}}. Ключ — "username:имя" или "phone:+7…". Имя поля — строчные буквы, цифры и «_», до 32 знаков; значение до 500 знаков; до 30 полей на получателя. |
nameExclusions | в теле | список строк. Кому писать без обращения по имени: ключи вида "username:имя" или "phone:+7…", не больше 20 000. |
secondTouch | в теле | объект. Второе касание: {enabled: да/нет (обязательно), days: 2, 3 или 5 (по умолчанию 3), audience: "read" — тем, кто прочитал, или "all" — всем (по умолчанию "read"), template: текст до 20 000 знаков, не больше 50 вариантов}. Текст должен отличаться от первого сообщения. С постом не сочетается. |
content | в теле | объект. Что отправлять. Не передавать или {kind: "text"} — текст из template. {kind: "post", post: {…}, textPlace: "before" | "after" | null} — пост: post как в «Проверить пост», textPlace добавляет текст отдельным сообщением до или после поста. Пересылка поста из канала работает только для получателей с username. |
baseLabel | в теле | строка. «База»: откуда эти получатели, до 60 знаков. Нужна, чтобы сравнивать базы в статистике. |
autoReply | в теле | объект. Автоответ на первое сообщение лида: {enabled: да/нет (обязательно), kind: "text" или "post", text: текст до 4096 знаков, варианты {а|б} можно, поля [[…]] нельзя, post: пост как в «Проверить пост», textPlace: "before", "after" или null, pauseFrom и pauseTo: пауза перед ответом, 5–900 с (30 и 165)}. |
curl -X POST "https://app.kelvintg.ru/api/v1/campaigns/rehearsal" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Проверка",
"template": "Здравствуйте! Это проверка.",
"recipientsText": "@synthetic_lead",
"accountIds": [
"ID_АККАУНТА"
]
}'Ответ:
{
"total": 1,
"variants": 1,
"samples": [
{
"recipient": "synthetic_lead",
"text": "Здравствуйте! Это проверка."
}
],
"excluded": 0,
"distribution": [
{
"accountId": "ID",
"label": "Анна",
"count": 1,
"sampleRecipients": [
{
"kind": "username",
"value": "synthetic_lead"
}
],
"estimate": {
"days": 1,
"remainingToday": 80,
"perDay": 80
}
}
],
"estimate": {
"days": 1,
"remainingToday": 80,
"perDay": 80
},
"schedule": {
"open": true,
"nextEligibleAt": null,| Отказ | Что случилось и что сделать |
|---|---|
| 400 | В списке есть строка, которая не похожа ни на username, ни на телефон, или получателей больше 20 000. Проверь список запросом «Проверить список получателей». |
| 400 | Все получатели уже в списке «Не писать». Отправлять некому. |
| 400 | В тексте есть поле [[…]], для которого у части получателей нет значения. Добавь запасной текст: [[город|вашем городе]]. |
Посчитать второе касание
POST /campaigns/ID_РАССЫЛКИ/second-touch/preview · право ключа: только чтение
Считает, сколько человек получат второе сообщение при таких настройках и когда. Ничего не сохраняет: чтобы включить второе касание, измени настройки рассылки.
| Поле | Где | Что это |
|---|---|---|
expectedRevision — обязательно | в теле | число. Номер версии revision из рассылки. |
secondTouch | в теле | объект. Второе касание: {enabled: да/нет (обязательно), days: 2, 3 или 5 (по умолчанию 3), audience: "read" — тем, кто прочитал, или "all" — всем (по умолчанию "read"), template: текст до 20 000 знаков, не больше 50 вариантов}. Текст должен отличаться от первого сообщения. С постом не сочетается. Без поля считаются сохранённые настройки. |
accountIds | в теле | список строк. Если хочешь прикинуть с другим набором аккаунтов. Без поля берутся аккаунты рассылки. |
schedule | в теле | объект. Когда можно отправлять: {timeZone: "Europe/Moscow" или "UTC", startLocal: "ГГГГ-ММ-ДДTЧЧ:ММ" (не раньше текущей минуты) или null, weekdays: дни недели 0–6, где 0 — воскресенье, intervals: от 1 до 4 отрезков {start: "ЧЧ:ММ", end: "ЧЧ:ММ"}}. Если конец раньше начала, отрезок переходит через полночь. Без поля берётся расписание рассылки. |
curl -X POST "https://app.kelvintg.ru/api/v1/campaigns/ID_РАССЫЛКИ/second-touch/preview" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"expectedRevision": 1,
"secondTouch": {
"enabled": true,
"days": 3,
"audience": "read",
"template": "Добрый день! Напоминаю о себе."
}
}'Ответ:
{
"revision": 1,
"upperBound": 1,
"eligibleNow": 0,
"scheduled": 0,
"awaitingFirst": 1,
"readCheckPending": 1,
"notReadByChecks": {},
"notReadFinal": 0,
"nextEligibleAt": null,
"sent": 0,
"unknown": 0,
"excludedByReason": {},
"accounts": [
{
"accountId": "ID",
"label": "Анна",
"upperBound": 1,
"eligibleNow": 0,
"scheduled": 0,
"sent": 0,
"unknown": 0,
"todayMax": 0,
"later": 0,
"nextEligibleAt": null,
"excludedByReason": {}
}
],
"todayMax": 0
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Рассылку изменили после того, как ты её прочитал. Запроси её заново и повтори с новым revision. |
| 400 | Текст второго касания совпадает с первым сообщением. Напиши другой. |
Создать рассылку или одно сообщение
POST /campaigns · право ключа: чтение и действия · нужен номер запроса
Создаёт рассылку-черновик: список получателей, текст и аккаунты. Отправка не начинается, пока ты не вызовешь «Запустить рассылку». Отдельного запроса «написать одному человеку» нет: это рассылка с одним получателем, как в примере, и затем запуск.
| Поле | Где | Что это |
|---|---|---|
name — обязательно | в теле | строка. Название рассылки, до 200 знаков. |
template — обязательно | в теле | строка. Текст сообщения, до 20 000 знаков со всеми вариантами. Варианты пишутся как {Здравствуйте|Добрый день}, поля из таблицы как [[город|запасной текст]], обращение по имени как [[имя]]. Каждый итоговый вариант не длиннее 4096 знаков. Можно не передавать, только если отправляешь пост без текста. |
recipientsText — обязательно | в теле | строка. Получатели, по одному в строке: username (5–32 знака, с @ или без, можно ссылкой t.me/имя) или телефон (8–15 цифр). Не больше 20 000. Повторы убираются сами, любая нераспознанная строка даёт отказ. |
accountIds — обязательно | в теле | список строк. С каких аккаунтов отправлять: хотя бы один аккаунт этого кабинета. Получатели раздаются по аккаунтам по кругу. |
schedule | в теле | объект. Когда можно отправлять: {timeZone: "Europe/Moscow" или "UTC", startLocal: "ГГГГ-ММ-ДДTЧЧ:ММ" (не раньше текущей минуты) или null, weekdays: дни недели 0–6, где 0 — воскресенье, intervals: от 1 до 4 отрезков {start: "ЧЧ:ММ", end: "ЧЧ:ММ"}}. Если конец раньше начала, отрезок переходит через полночь. Без поля рассылка идёт без расписания. |
pacing | в теле | объект. Темп. Любое поле можно не передавать, тогда берётся значение из скобок: batchMin и batchMax — сообщений подряд, 1–20 (2 и 5); waitMinSeconds и waitMaxSeconds — пауза между сообщениями, 10–1800 с (55 и 85); readMinSeconds и readMaxSeconds — перерыв между сериями, 30–600 с (90 и 240); readInBreaks — читать каналы в перерывах (да); spreadEnabled — растягивать отправку по времени (да); spreadMinutes — 15–480 (60). Минимум не больше максимума. |
recipientFields | в теле | объект. Поля из таблицы по получателям: {"username:synthetic_lead": {"город": "Казань"}}. Ключ — "username:имя" или "phone:+7…". Имя поля — строчные буквы, цифры и «_», до 32 знаков; значение до 500 знаков; до 30 полей на получателя. |
nameExclusions | в теле | список строк. Кому писать без обращения по имени: ключи вида "username:имя" или "phone:+7…", не больше 20 000. |
secondTouch | в теле | объект. Второе касание: {enabled: да/нет (обязательно), days: 2, 3 или 5 (по умолчанию 3), audience: "read" — тем, кто прочитал, или "all" — всем (по умолчанию "read"), template: текст до 20 000 знаков, не больше 50 вариантов}. Текст должен отличаться от первого сообщения. С постом не сочетается. |
content | в теле | объект. Что отправлять. Не передавать или {kind: "text"} — текст из template. {kind: "post", post: {…}, textPlace: "before" | "after" | null} — пост: post как в «Проверить пост», textPlace добавляет текст отдельным сообщением до или после поста. Пересылка поста из канала работает только для получателей с username. |
baseLabel | в теле | строка. «База»: откуда эти получатели, до 60 знаков. Нужна, чтобы сравнивать базы в статистике. |
autoReply | в теле | объект. Автоответ на первое сообщение лида: {enabled: да/нет (обязательно), kind: "text" или "post", text: текст до 4096 знаков, варианты {а|б} можно, поля [[…]] нельзя, post: пост как в «Проверить пост», textPlace: "before", "after" или null, pauseFrom и pauseTo: пауза перед ответом, 5–900 с (30 и 165)}. |
stopWarmup | в теле | да/нет. Передай true, если выбранный аккаунт сейчас на прогреве и ты согласен прогрев выключить. Без этого придёт отказ. |
curl -X POST "https://app.kelvintg.ru/api/v1/campaigns" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Idempotency-Key: order-0001" \
-H "Content-Type: application/json" \
-d '{
"name": "Проверка",
"template": "Здравствуйте! Это проверка.",
"recipientsText": "@synthetic_lead",
"accountIds": [
"ID_АККАУНТА"
]
}'Ответ:
{
"id": "ID",
"name": "Проверка",
"baseLabel": null,
"status": "pending",
"createdAt": "2026-10-10T10:00:00.000Z",
"schedule": null,
"scheduleStatus": null,
"editable": true,
"revision": 1,
"startedAt": null,
"secondTouch": {
"enabled": false,
"waiting": false,
"planned": 0,
"sent": 0
},
"post": null,
"autoReply": {
"enabled": false,
"sent": 0,
"waiting": 0,
"refused": 0,
"missed": 0
},
"total": 1
}| Отказ | Что случилось и что сделать |
|---|---|
| 400 | В списке есть строка, которая не похожа ни на username, ни на телефон, или получателей больше 20 000. Проверь список запросом «Проверить список получателей». |
| 400 | Все получатели уже в списке «Не писать». Отправлять некому. |
| 400 | В тексте есть поле [[…]], для которого у части получателей нет значения. Добавь запасной текст: [[город|вашем городе]]. |
| 409 | Один из аккаунтов на прогреве. Останови прогрев или повтори запрос с stopWarmup: true (с новым номером запроса). |
Изменить черновик рассылки
PATCH /campaigns/ID_РАССЫЛКИ · право ключа: чтение и действия
Заменяет черновик целиком: передавай все поля, как при создании, а не только изменённые. Работает, пока рассылку ни разу не запускали. После запуска меняются только настройки, для этого есть отдельный запрос.
| Поле | Где | Что это |
|---|---|---|
expectedRevision — обязательно | в теле | число. Номер версии revision, который ты видел в рассылке. Если рассылку успели изменить, придёт отказ, и ничего не затрётся. |
name — обязательно | в теле | строка. Название рассылки, до 200 знаков. |
template — обязательно | в теле | строка. Текст сообщения, до 20 000 знаков со всеми вариантами. Варианты пишутся как {Здравствуйте|Добрый день}, поля из таблицы как [[город|запасной текст]], обращение по имени как [[имя]]. Каждый итоговый вариант не длиннее 4096 знаков. Можно не передавать, только если отправляешь пост без текста. |
recipientsText — обязательно | в теле | строка. Получатели, по одному в строке: username (5–32 знака, с @ или без, можно ссылкой t.me/имя) или телефон (8–15 цифр). Не больше 20 000. Повторы убираются сами, любая нераспознанная строка даёт отказ. |
accountIds — обязательно | в теле | список строк. С каких аккаунтов отправлять: хотя бы один аккаунт этого кабинета. Получатели раздаются по аккаунтам по кругу. |
schedule | в теле | объект. Когда можно отправлять: {timeZone: "Europe/Moscow" или "UTC", startLocal: "ГГГГ-ММ-ДДTЧЧ:ММ" (не раньше текущей минуты) или null, weekdays: дни недели 0–6, где 0 — воскресенье, intervals: от 1 до 4 отрезков {start: "ЧЧ:ММ", end: "ЧЧ:ММ"}}. Если конец раньше начала, отрезок переходит через полночь. Если не передать, расписание снимется. |
pacing | в теле | объект. Темп. Любое поле можно не передавать, тогда берётся значение из скобок: batchMin и batchMax — сообщений подряд, 1–20 (2 и 5); waitMinSeconds и waitMaxSeconds — пауза между сообщениями, 10–1800 с (55 и 85); readMinSeconds и readMaxSeconds — перерыв между сериями, 30–600 с (90 и 240); readInBreaks — читать каналы в перерывах (да); spreadEnabled — растягивать отправку по времени (да); spreadMinutes — 15–480 (60). Минимум не больше максимума. Если не передать весь объект, темп вернётся к значениям из скобок. |
recipientFields | в теле | объект. Поля из таблицы по получателям: {"username:synthetic_lead": {"город": "Казань"}}. Ключ — "username:имя" или "phone:+7…". Имя поля — строчные буквы, цифры и «_», до 32 знаков; значение до 500 знаков; до 30 полей на получателя. |
nameExclusions | в теле | список строк. Кому писать без обращения по имени: ключи вида "username:имя" или "phone:+7…", не больше 20 000. Если не передать, останется прежний список. |
secondTouch | в теле | объект. Второе касание: {enabled: да/нет (обязательно), days: 2, 3 или 5 (по умолчанию 3), audience: "read" — тем, кто прочитал, или "all" — всем (по умолчанию "read"), template: текст до 20 000 знаков, не больше 50 вариантов}. Текст должен отличаться от первого сообщения. С постом не сочетается. Если не передать, второе касание выключится. |
content | в теле | объект. Что отправлять. Не передавать или {kind: "text"} — текст из template. {kind: "post", post: {…}, textPlace: "before" | "after" | null} — пост: post как в «Проверить пост», textPlace добавляет текст отдельным сообщением до или после поста. Пересылка поста из канала работает только для получателей с username. |
baseLabel | в теле | строка. «База»: откуда эти получатели, до 60 знаков. Нужна, чтобы сравнивать базы в статистике. Если не передать, останется прежняя. |
autoReply | в теле | объект. Автоответ на первое сообщение лида: {enabled: да/нет (обязательно), kind: "text" или "post", text: текст до 4096 знаков, варианты {а|б} можно, поля [[…]] нельзя, post: пост как в «Проверить пост», textPlace: "before", "after" или null, pauseFrom и pauseTo: пауза перед ответом, 5–900 с (30 и 165)}. Если не передать, автоответ выключится. |
curl -X PATCH "https://app.kelvintg.ru/api/v1/campaigns/ID_РАССЫЛКИ" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"expectedRevision": 1,
"name": "Проверка, вторая версия",
"template": "Здравствуйте! Это проверка.",
"recipientsText": "@synthetic_lead",
"accountIds": [
"ID_АККАУНТА"
]
}'Ответ:
{
"id": "ID",
"name": "Проверка, вторая версия",
"baseLabel": null,
"status": "pending",
"createdAt": "2026-10-10T10:00:00.000Z",
"schedule": null,
"scheduleStatus": null,
"editable": true,
"revision": 2,
"startedAt": null,
"secondTouch": {
"enabled": false,
"waiting": false,
"planned": 0,
"sent": 0
},
"post": null,
"autoReply": {
"enabled": false,
"sent": 0,
"waiting": 0,
"refused": 0,
"missed": 0
},
"total": 1
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Рассылку уже запускали: черновик изменить нельзя. Меняй настройки запросом «Изменить настройки рассылки». |
| 409 | Рассылку изменили после того, как ты её прочитал. Запроси её заново и повтори с новым revision. |
| 400 | В списке есть строка, которая не похожа ни на username, ни на телефон, или получателей больше 20 000. Проверь список запросом «Проверить список получателей». |
| 400 | Все получатели уже в списке «Не писать». Отправлять некому. |
Изменить настройки рассылки
PATCH /campaigns/ID_РАССЫЛКИ/settings · право ключа: чтение и действия
Меняет название, аккаунты, расписание, темп, второе касание и автоответ. Работает и для запущенной рассылки, текст и получателей не трогает. Расписание и темп передавай каждый раз: без них они сбросятся.
| Поле | Где | Что это |
|---|---|---|
expectedRevision — обязательно | в теле | число. Номер версии revision из рассылки. Если он устарел, придёт отказ. |
name — обязательно | в теле | строка. Название рассылки, до 200 знаков. |
accountIds — обязательно | в теле | список строк. Аккаунты рассылки, хотя бы один. Добавленный аккаунт начнёт брать получателей из общей очереди, убранный перестанет. |
schedule | в теле | объект. Когда можно отправлять: {timeZone: "Europe/Moscow" или "UTC", startLocal: "ГГГГ-ММ-ДДTЧЧ:ММ" (не раньше текущей минуты) или null, weekdays: дни недели 0–6, где 0 — воскресенье, intervals: от 1 до 4 отрезков {start: "ЧЧ:ММ", end: "ЧЧ:ММ"}}. Если конец раньше начала, отрезок переходит через полночь. Если не передать, расписание снимется. |
pacing | в теле | объект. Темп. Любое поле можно не передавать, тогда берётся значение из скобок: batchMin и batchMax — сообщений подряд, 1–20 (2 и 5); waitMinSeconds и waitMaxSeconds — пауза между сообщениями, 10–1800 с (55 и 85); readMinSeconds и readMaxSeconds — перерыв между сериями, 30–600 с (90 и 240); readInBreaks — читать каналы в перерывах (да); spreadEnabled — растягивать отправку по времени (да); spreadMinutes — 15–480 (60). Минимум не больше максимума. Если не передать весь объект, темп вернётся к значениям из скобок. |
secondTouch | в теле | объект. Второе касание: {enabled: да/нет (обязательно), days: 2, 3 или 5 (по умолчанию 3), audience: "read" — тем, кто прочитал, или "all" — всем (по умолчанию "read"), template: текст до 20 000 знаков, не больше 50 вариантов}. Текст должен отличаться от первого сообщения. С постом не сочетается. Если не передать, останется как было. |
autoReply | в теле | объект. Автоответ на первое сообщение лида: {enabled: да/нет (обязательно), kind: "text" или "post", text: текст до 4096 знаков, варианты {а|б} можно, поля [[…]] нельзя, post: пост как в «Проверить пост», textPlace: "before", "after" или null, pauseFrom и pauseTo: пауза перед ответом, 5–900 с (30 и 165)}. Если не передать, останется как было. |
baseLabel | в теле | строка. «База», до 60 знаков. Если не передать, останется прежняя. |
stopWarmup | в теле | да/нет. Передай true, если добавляешь аккаунт, который сейчас на прогреве, и согласен прогрев выключить. |
curl -X PATCH "https://app.kelvintg.ru/api/v1/campaigns/ID_РАССЫЛКИ/settings" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"expectedRevision": 1,
"name": "Проверка",
"accountIds": [
"ID_АККАУНТА"
]
}'Ответ:
{
"id": "ID",
"name": "Проверка",
"baseLabel": null,
"status": "pending",
"createdAt": "2026-10-10T10:00:00.000Z",
"schedule": null,
"scheduleStatus": null,
"editable": true,
"revision": 2,
"startedAt": null,
"secondTouch": {
"enabled": false,
"waiting": false,
"planned": 0,
"sent": 0
},
"post": null,
"autoReply": {
"enabled": false,
"sent": 0,
"waiting": 0,
"refused": 0,
"missed": 0
},
"total": 1
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Рассылка отменена, изменить её нельзя. |
| 409 | Рассылку изменили после того, как ты её прочитал. Запроси её заново и повтори с новым revision. |
| 400 | Начало расписания в прошлом. Поставь время не раньше текущей минуты. |
Запустить рассылку
POST /campaigns/ID_РАССЫЛКИ/start · право ключа: чтение и действия
Запускает созданную рассылку или продолжает её после паузы: телефоны начнут отправлять сообщения в своём обычном темпе и в пределах дневных лимитов аккаунтов. Если в кабинете нажато «Остановить всё», запрос примется, но отправка начнётся только после возобновления работы человеком.
| Поле | Где | Что это |
|---|---|---|
stopWarmup | в теле | да/нет. Передай true, если аккаунт рассылки сейчас на прогреве и ты согласен прогрев выключить. |
curl -X POST "https://app.kelvintg.ru/api/v1/campaigns/ID_РАССЫЛКИ/start" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{}'Ответ:
{
"id": "ID",
"name": "Проверка",
"baseLabel": null,
"status": "running",
"createdAt": "2026-10-10T10:00:00.000Z",
"schedule": null,
"scheduleStatus": null,
"editable": false,
"revision": 2,
"startedAt": "2026-10-10T10:00:00.000Z",
"secondTouch": {
"enabled": false,
"waiting": false,
"planned": 0,
"sent": 0
},
"post": null,
"autoReply": {
"enabled": false,
"sent": 0,
"waiting": 0,
"refused": 0,
"missed": 0
},
"total": 1
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Рассылка отменена. Запустить её снова нельзя, создай новую. |
| 409 | Отправлять некому: в рассылке не осталось получателей в очереди. |
| 409 | Один из аккаунтов на прогреве. Останови прогрев или повтори запрос с stopWarmup: true. |
Поставить рассылку на паузу
POST /campaigns/ID_РАССЫЛКИ/pause · право ключа: чтение и действия
Останавливает выдачу новых сообщений телефонам. Сообщение, которое телефон уже начал отправлять, он закончит. Продолжить можно запросом «Запустить рассылку».
curl -X POST "https://app.kelvintg.ru/api/v1/campaigns/ID_РАССЫЛКИ/pause" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{}'Ответ:
{
"id": "ID",
"name": "Проверка",
"baseLabel": null,
"status": "paused",
"createdAt": "2026-10-10T10:00:00.000Z",
"schedule": null,
"scheduleStatus": null,
"editable": false,
"revision": 3,
"startedAt": "2026-10-10T10:00:00.000Z",
"secondTouch": {
"enabled": false,
"waiting": false,
"planned": 0,
"sent": 0
},
"post": null,
"autoReply": {
"enabled": false,
"sent": 0,
"waiting": 0,
"refused": 0,
"missed": 0
},
"total": 1
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Рассылка отменена, ставить её на паузу незачем. |
Отменить рассылку
POST /campaigns/ID_РАССЫЛКИ/cancel · право ключа: чтение и действия
Отменяет рассылку насовсем: все, кто ещё в очереди, сообщение не получат, и запустить её снова нельзя. Сообщение, которое телефон уже начал отправлять, он закончит. Если хочешь продолжить позже, ставь на паузу.
curl -X POST "https://app.kelvintg.ru/api/v1/campaigns/ID_РАССЫЛКИ/cancel" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{}'Ответ:
{
"id": "ID",
"name": "Проверка",
"baseLabel": null,
"status": "cancelled",
"createdAt": "2026-10-10T10:00:00.000Z",
"schedule": null,
"scheduleStatus": null,
"editable": false,
"revision": 2,
"startedAt": null,
"secondTouch": {
"enabled": false,
"waiting": false,
"planned": 0,
"sent": 0
},
"post": null,
"autoReply": {
"enabled": false,
"sent": 0,
"waiting": 0,
"refused": 0,
"missed": 0
},
"total": 1
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Рассылка уже отменена. |
Убрать в корзину или вернуть
POST /campaigns/trash · право ключа: чтение и действия
Переносит рассылки в корзину или возвращает из неё. Идущая рассылка при этом встаёт на паузу. Уже отправленные сообщения остаются в статистике.
| Поле | Где | Что это |
|---|---|---|
ids — обязательно | в теле | список строк. Какие рассылки: от 1 до 500 номеров. |
action — обязательно | в теле | строка. "delete" — в корзину, "restore" — вернуть из корзины. |
curl -X POST "https://app.kelvintg.ru/api/v1/campaigns/trash" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"ids": [
"ID_РАССЫЛКИ"
],
"action": "delete"
}'Ответ:
{
"ok": true,
"ids": [
"ID"
]
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Телефон прямо сейчас отправляет сообщение этой рассылки. Поставь её на паузу, дождись конца отправки и повтори. Ни одна рассылка из запроса не изменилась. |
Наборы настроек
Список наборов
GET /campaign-playbooks · право ключа: только чтение
Отдаёт сохранённые наборы настроек рассылки: текст, темп, расписание и аккаунты. Получателей в наборах нет.
curl "https://app.kelvintg.ru/api/v1/campaign-playbooks" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"items": []
}Один набор
GET /campaign-playbooks/ID_НАБОРА · право ключа: только чтение
Отдаёт набор целиком вместе с номером версии version. Этот номер пригодится, чтобы изменить набор и не затереть чужую правку.
curl "https://app.kelvintg.ru/api/v1/campaign-playbooks/ID_НАБОРА" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"id": "ID",
"name": "Первое касание",
"version": 1,
"template": "{Здравствуйте|Добрый день}! Это проверка.",
"accountIds": [
"ID"
],
"pacing": {
"batchMin": 2,
"batchMax": 5,
"waitMinSeconds": 55,
"waitMaxSeconds": 85,
"readMinSeconds": 90,
"readMaxSeconds": 240,
"readInBreaks": true,
"spreadEnabled": true,
"spreadMinutes": 60
},
"schedule": null,
"recipientFieldSchema": [],
"requiredChecks": [
"Проверить список получателей"
],
"createdAt": "2026-10-10T10:00:00.000Z",
"updatedAt": "2026-10-10T10:00:00.000Z"
}Что даст набор
GET /campaign-playbooks/ID_НАБОРА/apply-preview · право ключа: только чтение
Показывает, что подставится в новую рассылку из набора, и каких аккаунтов из него уже нет в кабинете. Рассылку не создаёт: для этого возьми данные набора и вызови «Создать рассылку».
curl "https://app.kelvintg.ru/api/v1/campaign-playbooks/ID_НАБОРА/apply-preview" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"id": "ID",
"name": "Первое касание",
"version": 1,
"template": "{Здравствуйте|Добрый день}! Это проверка.",
"accountIds": [
"ID"
],
"pacing": {
"batchMin": 2,
"batchMax": 5,
"waitMinSeconds": 55,
"waitMaxSeconds": 85,
"readMinSeconds": 90,
"readMaxSeconds": 240,
"readInBreaks": true,
"spreadEnabled": true,
"spreadMinutes": 60
},
"schedule": null,
"recipientFieldSchema": [],
"requiredChecks": [
"Проверить список получателей"
],
"createdAt": "2026-10-10T10:00:00.000Z",
"updatedAt": "2026-10-10T10:00:00.000Z",
"accounts": [
{
"id": "ID",
"label": "Анна",
"aiStatus": "off"
}
],
"missingAccountIds": []
}Сохранить набор
POST /campaign-playbooks · право ключа: чтение и действия · нужен номер запроса
Сохраняет настройки рассылки, чтобы не вводить их каждый раз. Получатели в набор не входят.
| Поле | Где | Что это |
|---|---|---|
name — обязательно | в теле | строка. Название набора, до 200 знаков. |
template — обязательно | в теле | строка. Текст сообщения с вариантами {а|б} и полями [[поле|запасной текст]]. Проверяется так же, как в рассылке. |
accountIds — обязательно | в теле | список строк. Аккаунты, с которых обычно идёт такая рассылка: хотя бы один аккаунт кабинета. |
schedule | в теле | объект. Когда можно отправлять: {timeZone: "Europe/Moscow" или "UTC", startLocal: "ГГГГ-ММ-ДДTЧЧ:ММ" (не раньше текущей минуты) или null, weekdays: дни недели 0–6, где 0 — воскресенье, intervals: от 1 до 4 отрезков {start: "ЧЧ:ММ", end: "ЧЧ:ММ"}}. Если конец раньше начала, отрезок переходит через полночь. |
pacing | в теле | объект. Темп. Любое поле можно не передавать, тогда берётся значение из скобок: batchMin и batchMax — сообщений подряд, 1–20 (2 и 5); waitMinSeconds и waitMaxSeconds — пауза между сообщениями, 10–1800 с (55 и 85); readMinSeconds и readMaxSeconds — перерыв между сериями, 30–600 с (90 и 240); readInBreaks — читать каналы в перерывах (да); spreadEnabled — растягивать отправку по времени (да); spreadMinutes — 15–480 (60). Минимум не больше максимума. |
requiredChecks | в теле | список строк. Что проверить перед запуском: до 20 пунктов, каждый до 200 знаков. |
curl -X POST "https://app.kelvintg.ru/api/v1/campaign-playbooks" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Idempotency-Key: order-0001" \
-H "Content-Type: application/json" \
-d '{
"name": "Первое касание",
"template": "{Здравствуйте|Добрый день}! Это проверка.",
"accountIds": [
"ID_АККАУНТА"
],
"requiredChecks": [
"Проверить список получателей"
]
}'Ответ:
{
"id": "ID",
"name": "Первое касание",
"version": 1,
"template": "{Здравствуйте|Добрый день}! Это проверка.",
"accountIds": [
"ID"
],
"pacing": {
"batchMin": 2,
"batchMax": 5,
"waitMinSeconds": 55,
"waitMaxSeconds": 85,
"readMinSeconds": 90,
"readMaxSeconds": 240,
"readInBreaks": true,
"spreadEnabled": true,
"spreadMinutes": 60
},
"schedule": null,
"recipientFieldSchema": [],
"requiredChecks": [
"Проверить список получателей"
],
"createdAt": "2026-10-10T10:00:00.000Z",
"updatedAt": "2026-10-10T10:00:00.000Z"
}Изменить набор
PUT /campaign-playbooks/ID_НАБОРА · право ключа: чтение и действия
Заменяет набор целиком: передавай все поля, а не только изменённые. Расписание, темп и список проверок без своих полей сбросятся. Уже созданные рассылки не меняются.
| Поле | Где | Что это |
|---|---|---|
name — обязательно | в теле | строка. Название набора, до 200 знаков. |
template — обязательно | в теле | строка. Текст сообщения с вариантами {а|б} и полями [[поле|запасной текст]]. Проверяется так же, как в рассылке. |
accountIds — обязательно | в теле | список строк. Аккаунты, с которых обычно идёт такая рассылка: хотя бы один аккаунт кабинета. |
schedule | в теле | объект. Когда можно отправлять: {timeZone: "Europe/Moscow" или "UTC", startLocal: "ГГГГ-ММ-ДДTЧЧ:ММ" (не раньше текущей минуты) или null, weekdays: дни недели 0–6, где 0 — воскресенье, intervals: от 1 до 4 отрезков {start: "ЧЧ:ММ", end: "ЧЧ:ММ"}}. Если конец раньше начала, отрезок переходит через полночь. |
pacing | в теле | объект. Темп. Любое поле можно не передавать, тогда берётся значение из скобок: batchMin и batchMax — сообщений подряд, 1–20 (2 и 5); waitMinSeconds и waitMaxSeconds — пауза между сообщениями, 10–1800 с (55 и 85); readMinSeconds и readMaxSeconds — перерыв между сериями, 30–600 с (90 и 240); readInBreaks — читать каналы в перерывах (да); spreadEnabled — растягивать отправку по времени (да); spreadMinutes — 15–480 (60). Минимум не больше максимума. |
requiredChecks | в теле | список строк. Что проверить перед запуском: до 20 пунктов, каждый до 200 знаков. |
version | в теле | число. Номер версии, который ты видел. Если набор успели изменить, придёт отказ. Без поля набор перезапишется без проверки. |
curl -X PUT "https://app.kelvintg.ru/api/v1/campaign-playbooks/ID_НАБОРА" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Первое касание, вечер",
"template": "{Здравствуйте|Добрый день}! Это проверка.",
"accountIds": [
"ID_АККАУНТА"
],
"requiredChecks": [
"Проверить список получателей"
]
}'Ответ:
{
"id": "ID",
"name": "Первое касание, вечер",
"version": 2,
"template": "{Здравствуйте|Добрый день}! Это проверка.",
"accountIds": [
"ID"
],
"pacing": {
"batchMin": 2,
"batchMax": 5,
"waitMinSeconds": 55,
"waitMaxSeconds": 85,
"readMinSeconds": 90,
"readMaxSeconds": 240,
"readInBreaks": true,
"spreadEnabled": true,
"spreadMinutes": 60
},
"schedule": null,
"recipientFieldSchema": [],
"requiredChecks": [
"Проверить список получателей"
],
"createdAt": "2026-10-10T10:00:00.000Z",
"updatedAt": "2026-10-10T10:00:00.000Z"
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Набор изменили после того, как ты его прочитал. Запроси его заново и повтори с новым version. |
Удалить набор
DELETE /campaign-playbooks/ID_НАБОРА · право ключа: чтение и действия
Удаляет набор насовсем, вернуть его нельзя. Рассылки, созданные по этому набору, остаются как были.
curl -X DELETE "https://app.kelvintg.ru/api/v1/campaign-playbooks/ID_НАБОРА" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"ok": true,
"id": "ID"
}«Не писать»
Список «Не писать»
GET /blocklist · право ключа: только чтение
Отдаёт всех, кому кабинет не пишет: username и телефоны, причину и дату добавления. Username и телефон одного человека между собой не связываются: добавляй оба, если знаешь оба.
curl "https://app.kelvintg.ru/api/v1/blocklist" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"entries": []
}Добавить в «Не писать»
POST /blocklist · право ключа: чтение и действия
Добавляет людей в список и сразу отменяет им сообщения, которые ещё в очереди, во всех рассылках кабинета. Сообщение, которое телефон уже начал отправлять, может уйти. В ответе видно, кто добавлен, кто уже был в списке и какие строки не распознаны.
| Поле | Где | Что это |
|---|---|---|
text — обязательно | в теле | строка. Кого добавить, по одному в строке: username или телефон, как в списке получателей. |
reason | в теле | строка. Причина, до 200 знаков. Видна только в кабинете. |
curl -X POST "https://app.kelvintg.ru/api/v1/blocklist" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "@synthetic_blocked",
"reason": "Попросил не писать"
}'Ответ:
{
"added": [
{
"line": 1,
"kind": "username",
"value": "synthetic_blocked"
}
],
"duplicates": [],
"invalid": [],
"cancelledTasks": 0
}Убрать из «Не писать»
DELETE /blocklist · право ключа: чтение и действия
Убирает одного человека из списка. Сообщения, отменённые из-за списка раньше, не возвращаются: человек попадёт только в новые рассылки. Поля передаются в теле запроса.
| Поле | Где | Что это |
|---|---|---|
kind — обязательно | в теле | строка. "username" или "phone". Должен совпасть с тем, что написано в value. |
value — обязательно | в теле | строка. Один получатель: @имя, ссылка t.me/имя или телефон. |
curl -X DELETE "https://app.kelvintg.ru/api/v1/blocklist" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "username",
"value": "@synthetic_blocked"
}'Ответ:
{
"ok": true,
"removed": true
}Чаты и ответы лидам
Что телефоны прочитали в Telegram
GET /dialog-list · право ключа: только чтение
Отдаёт сводку по каждому аккаунту: сколько чатов телефон увидел в папке «Лиды», сколько из них ответили, прочитали и не прочитали. В строках есть названия чатов и начало сообщений, если они не нужны, запроси без строк.
| Поле | Где | Что это |
|---|---|---|
rows | в адресе | строка. "0" — только сводка, без строк по чатам. Без параметра строки приходят, до 3000 на аккаунт. |
curl "https://app.kelvintg.ru/api/v1/dialog-list?rows=0" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"accounts": [],
"firstRead": []
}Новые сообщения лидов
GET /chats/incoming · право ключа: только чтение
Отдаёт входящие сообщения лидов по всему кабинету по порядку. Запомни after из ответа и передай его в следующий раз: так ты получишь только новое, без пропусков и повторов. Наших сообщений здесь нет.
| Поле | Где | Что это |
|---|---|---|
after | в адресе | число. Значение after из прошлого ответа. По умолчанию 0, то есть с самого начала. |
limit | в адресе | число. Сколько сообщений отдать, 1–500. По умолчанию 100. |
curl "https://app.kelvintg.ru/api/v1/chats/incoming?after=0&limit=100" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"messages": [
{
"id": 1,
"chatId": "chat-1",
"accountId": "ID",
"name": "Мария",
"username": "synthetic_lead",
"text": "Здравствуйте!",
"at": "2026-10-10T09:30:00.000Z",
"receivedAt": "2026-10-10T09:30:00.000Z",
"voice": false
},
"… ещё 1"
],
"after": 2,
"more": false
}Список чатов
GET /chats · право ключа: только чтение
Отдаёт чаты с лидами, свежие сверху: имя, последнее сообщение, сколько непрочитанных и ждёт ли чат ответа. Чаты появляются по мере того, как телефоны передают их в кабинет.
| Поле | Где | Что это |
|---|---|---|
offset | в адресе | число. Сколько чатов пропустить, 0–1 000 000. По умолчанию 0. |
limit | в адресе | число. Сколько чатов отдать, 50–500. По умолчанию 50, меньше 50 не бывает. |
account | в адресе | строка. Чаты одного аккаунта: его номер из списка аккаунтов. "none" — чаты, у которых аккаунт ещё не определён. |
unread | в адресе | строка. "1" — только чаты, которые ждут ответа. Сильнее, чем filter. |
filter | в адресе | строка. "replied" — лид написал хотя бы раз, "waiting" — последнее сообщение наше. |
q | в адресе | строка. Поиск по имени или username, первые 100 знаков. |
curl "https://app.kelvintg.ru/api/v1/chats?limit=50&unread=1" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"chats": [
{
"id": "chat-1",
"accountId": "ID",
"name": "Мария",
"username": "synthetic_lead",
"needsReply": true,
"updatedAt": "2026-10-10T09:30:00.000Z",
"lastText": "Сколько стоит консультация?",
"lastFrom": "lead",
"unread": 2,
"queuedReply": null,
"snoozedUntil": null
}
],
"total": 1
}Переписка в чате
GET /chats/ID_ДИАЛОГА · право ключа: только чтение
Отдаёт чат, до 100 последних сообщений и ответы, которые ты поставил в очередь, с их состоянием. В переписке то, что телефон успел передать в кабинет: до ответа лиду телефон в чат не заходит.
| Поле | Где | Что это |
|---|---|---|
before | в адресе | число. Номер самого старого сообщения, которое у тебя уже есть: придут до 100 сообщений старше него. |
curl "https://app.kelvintg.ru/api/v1/chats/ID_ДИАЛОГА" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"chat": {
"id": "chat-1",
"accountId": "ID",
"name": "Мария",
"username": "synthetic_lead",
"needsReply": true,
"updatedAt": "2026-10-10T09:30:00.000Z"
},
"read": {
"readAt": null,
"state": "never",
"phone": "offline",
"blocked": null,
"failure": null
},
"messages": [
{
"id": 1,
"from": "lead",
"text": "Здравствуйте!",
"at": "2026-10-10T09:30:00.000Z",
"receivedAt": "2026-10-10T09:30:00.000Z",
"voice": null,
"readByLead": false
},
"… ещё 1"
],
"replies": [
{
"id": "ID",
"text": "Здравствуйте! Это проверка.",
"state": "pending",
"reason": null,
"createdAt": "2026-10-10T10:00:00.000Z",
"updatedAt": "2026-10-10T10:00:00.000Z"Узнать судьбу ответа
GET /chats/reply-requests/НОМЕР_ЗАПРОСА · право ключа: только чтение
Показывает, что стало с ответом, по номеру из «Idempotency-Key», с которым ты его отправлял. Нужен, когда ответ сервера потерялся: сначала спроси здесь, а не отправляй заново. Состояние unknown значит «вероятно отправлено», повторять такой ответ не надо.
curl "https://app.kelvintg.ru/api/v1/chats/reply-requests/НОМЕР_ЗАПРОСА" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"taskId": "ID",
"state": "pending"
}| Отказ | Что случилось и что сделать |
|---|---|
| 404 | Ответа с таким номером запроса нет: он не был принят. Можно отправить снова. |
Ответить лиду
POST /chats/ID_ДИАЛОГА/reply · право ключа: чтение и действия · нужен номер запроса
Ставит ответ в очередь телефона: он отправит его с того аккаунта, который ведёт чат, когда освободится. Если этот чат вёл ИИ, дальше его ведёшь ты. Повтор запроса с тем же номером в заголовке «Idempotency-Key» второе сообщение не создаст.
| Поле | Где | Что это |
|---|---|---|
text — обязательно | в теле | строка. Текст ответа, от 1 до 4096 знаков. |
curl -X POST "https://app.kelvintg.ru/api/v1/chats/ID_ДИАЛОГА/reply" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Idempotency-Key: order-0001" \
-H "Content-Type: application/json" \
-d '{
"text": "Здравствуйте! Это проверка."
}'Ответ:
{
"ok": true,
"taskId": "ID",
"taskState": "pending"
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Собеседник в списке «Не писать». Убери его оттуда, если хочешь ответить. |
| 409 | Лид ещё не написал, а его username неизвестен. Ответить получится после его первого сообщения. |
| 409 | Аккаунт этого чата удалён или не определён. Ответить с него нельзя. |
| 410 | Ответы из кабинета сейчас выключены. Напиши в поддержку KELVIN TG. |
Отменить ответ
POST /chats/replies/ID_ОТВЕТА/cancel · право ключа: чтение и действия
Отменяет ответ, пока он ждёт в очереди. Номер ответа — taskId из ответа на «Ответить лиду». Если телефон уже взял ответ в работу, отменить его нельзя.
curl -X POST "https://app.kelvintg.ru/api/v1/chats/replies/ID_ОТВЕТА/cancel" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{}'Ответ:
{
"ok": true
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Телефон уже отправляет этот ответ или закончил. Отменить его нельзя. |
Сверить чат с телефоном
POST /chats/ID_ДИАЛОГА/read · право ключа: чтение и действия
Просит телефон открыть чат и передать в кабинет свежую переписку. Это задание в очереди телефона: результат появится в запросе «Переписка в чате», когда телефон до него дойдёт.
| Поле | Где | Что это |
|---|---|---|
reason | в теле | строка. "opened" — мягкая сверка, не чаще раза в 2 минуты на чат. Без поля сверка запрашивается всегда. |
curl -X POST "https://app.kelvintg.ru/api/v1/chats/ID_ДИАЛОГА/read" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{}'Ответ:
{
"readAt": null,
"state": "queued",
"phone": "offline",
"blocked": null
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Сверить можно после первого ответа лида: пока KELVIN не знает, как найти этот чат на телефоне. |
| 409 | Телефон этого чата отключён от кабинета или на нём старая версия KELVIN TG. Подключи или обнови телефон. |
Отметить прочитанным в кабинете
POST /chats/ID_ДИАЛОГА/seen · право ключа: чтение и действия
Убирает счётчик непрочитанных у чата в кабинете. В Telegram ничего не меняется: лид не увидит, что сообщение прочитано.
| Поле | Где | Что это |
|---|---|---|
upTo — обязательно | в теле | строка. Дата и время самого свежего сообщения лида, которое ты показал, в виде 2026-10-10T09:00:00.000Z. Всё, что раньше, считается прочитанным. |
curl -X POST "https://app.kelvintg.ru/api/v1/chats/ID_ДИАЛОГА/seen" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"upTo": "2026-10-10T09:00:00.000Z"
}'Ответ:
{
"ok": true
}Снять «ждёт ответа»
POST /chats/ID_ДИАЛОГА/review · право ключа: чтение и действия
Отмечает, что отвечать на этот чат не нужно, и убирает его из тех, что ждут ответа. Новое сообщение лида вернёт отметку.
curl -X POST "https://app.kelvintg.ru/api/v1/chats/ID_ДИАЛОГА/review" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{}'Ответ:
{
"ok": true
}Обновить список чатов
POST /dialog-list/refresh · право ключа: чтение и действия
Просит телефоны заново прочитать список чатов в Telegram. Это задание в очереди: телефон выполнит его, когда будет свободен и на связи. В ответе queued — сколько заданий поставлено.
| Поле | Где | Что это |
|---|---|---|
accountId | в теле | строка. Обновить только этот аккаунт. Без поля — все включённые аккаунты кабинета. |
rows | в теле | число. Сколько строк списка прочитать, 1–3000. Без поля KELVIN считает сам по числу отправок аккаунта. |
curl -X POST "https://app.kelvintg.ru/api/v1/dialog-list/refresh" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "ID_АККАУНТА"
}'Ответ:
{
"queued": 1,
"accounts": 1,
"stopped": true
}ИИ-ответы
Чаты, которые ждут человека
GET /ai/queue · право ключа: чтение и действия
Отдаёт чаты, которые ИИ передал человеку, с причиной по-русски, и чаты с готовым черновиком ответа. Нужен ключ с правом на действия: при этом запросе ИИ заодно ставит в очередь следующую часть своего ответа из нескольких сообщений.
curl "https://app.kelvintg.ru/api/v1/ai/queue" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"items": []
}Статистика ИИ-ответов
GET /ai/stats · право ключа: только чтение
Отдаёт, сколько ответов ИИ подготовил за период и сколько из них приняты. Пустое значение вместо числа значит «данных пока нет», а не ноль. Текстов переписки в ответе нет.
| Поле | Где | Что это |
|---|---|---|
days | в адресе | число. За сколько дней считать, 1–30. По умолчанию 7. |
curl "https://app.kelvintg.ru/api/v1/ai/stats?days=7" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"days": 7,
"provider": "none",
"external": true,
"dailyRequests": 0,
"today": {
"requests": 0,
"errors": 0,
"reserved": 0
},
"drafts": 0,
"proposed": null,
"accepted": null,
"confirmed": null,
"handoff": null,
"rejected": null,
"stale": null,
"unknown": null,
"byReason": []
}Аккаунты и телефоны
Список аккаунтов
GET /accounts · право ключа: только чтение
Отдаёт все аккаунты Telegram в кабинете: лимиты, сколько отправлено сегодня, идёт ли прогрев и почему аккаунт сейчас не пишет, если не пишет. Удалённые аккаунты тоже в списке, у них заполнено deletedAt. Счётчики идут с начала суток по Москве.
curl "https://app.kelvintg.ru/api/v1/accounts" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"accounts": [
{
"id": "ID",
"deviceId": "ID",
"label": "Анна",
"phone": "+12025550401",
"enabled": true,
"deletedAt": null,
"messageLimit": 80,
"effectiveMessageLimit": 80,
"phoneSearchLimit": 15,
"taskDelayMin": 6,
"taskDelayMax": 6,
"accountDelayMin": 0,
"accountDelayMax": 0,
"searchDelayMin": 0
}
]
}Список телефонов
GET /devices · право ключа: только чтение
Отдаёт телефоны кабинета: на связи ли телефон, чем занят, версии Android, Telegram и KELVIN TG. Телефон считается не на связи, если молчит дольше 45 секунд. Отключённые телефоны в списке есть, удалённых нет.
curl "https://app.kelvintg.ru/api/v1/devices" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"devices": [
{
"id": "ID",
"name": "Телефон 1",
"lastSeen": null,
"status": "offline",
"androidVersion": null,
"telegramVersion": null,
"accessibilityEnabled": false,
"keyboardEnabled": null,
"power": null,
"screenUnlocked": false,
"networkConnected": false,
"liveEnabled": false,
"manualScreen": false,
"networkGroup": null
}
]
}Лента аккаунта
GET /accounts/ID_АККАУНТА/timeline · право ключа: только чтение
Отдаёт всё, что происходило с аккаунтом за последние дни, свежее сверху: отправки, прогрев, проверки, остановки. В ленте только статусы, без текстов и номеров. Не больше 3000 записей.
| Поле | Где | Что это |
|---|---|---|
days | в адресе | число. За сколько дней, 1–30. По умолчанию 7. |
curl "https://app.kelvintg.ru/api/v1/accounts/ID_АККАУНТА/timeline?days=7" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"accountId": "ID",
"days": 7,
"since": "2026-10-03T10:00:00.000Z",
"truncated": false,
"items": [
{
"at": "2026-10-10T10:00:00.000Z",
"type": "account",
"event": "account_created",
"changes": null
}
]
}Добавить аккаунт
POST /accounts · право ключа: чтение и действия · нужен номер запроса
Добавляет аккаунт Telegram к телефону в кабинете. Войти в этот аккаунт в Telegram на телефоне нужно руками, запрос этого не делает. На одном телефоне в одном приложении Telegram не больше трёх аккаунтов.
| Поле | Где | Что это |
|---|---|---|
deviceId — обязательно | в теле | строка. Телефон из списка телефонов. |
label — обязательно | в теле | строка. Название аккаунта в кабинете, 1–100 знаков. |
phone — обязательно | в теле | строка. Номер аккаунта: 8–15 цифр, можно с «+», пробелами, скобками и дефисами. |
enabled | в теле | да/нет. Включён ли аккаунт. По умолчанию да. |
clientId | в теле | строка. Какое приложение Telegram на телефоне: основное или второе. Без поля — основное. |
replaceSettings | в теле | да/нет. Только если возвращаешь удалённый аккаунт с тем же номером: true — взять лимиты из этого запроса, иначе вернутся прежние. |
messageLimit | в теле | число. Сколько сообщений в сутки отправляет аккаунт, 0–100. По умолчанию 80. |
phoneSearchLimit | в теле | число. Сколько получателей в сутки искать по номеру телефона, 0–15. По умолчанию 15. |
taskDelayMin | в теле | число. Пауза между сообщениями, от: 0–86 400 с. По умолчанию 6. Не больше taskDelayMax. |
taskDelayMax | в теле | число. Пауза между сообщениями, до: 0–86 400 с. По умолчанию 6. |
accountDelayMin | в теле | число. Пауза при смене аккаунта, от: 0–86 400 с. По умолчанию 0. Не больше accountDelayMax. |
accountDelayMax | в теле | число. Пауза при смене аккаунта, до: 0–86 400 с. По умолчанию 0. |
searchDelayMin | в теле | число. Пауза перед поиском по номеру, от: 0–86 400 с. По умолчанию 0. Не больше searchDelayMax. |
searchDelayMax | в теле | число. Пауза перед поиском по номеру, до: 0–86 400 с. По умолчанию 0. |
curl -X POST "https://app.kelvintg.ru/api/v1/accounts" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Idempotency-Key: order-0001" \
-H "Content-Type: application/json" \
-d '{
"deviceId": "ID_ТЕЛЕФОНА",
"label": "Аккаунт 2",
"phone": "+70000000002"
}'Ответ:
{
"id": "ID",
"deviceId": "ID",
"label": "Аккаунт 2",
"phone": "+70000000002",
"enabled": true,
"deletedAt": null,
"messageLimit": 80,
"effectiveMessageLimit": 80,
"phoneSearchLimit": 15,
"taskDelayMin": 6,
"taskDelayMax": 6,
"accountDelayMin": 0,
"accountDelayMax": 0,
"searchDelayMin": 0
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Этот номер уже есть в кабинете или занят в другом. Свой аккаунт найди в списке, про чужой напиши в поддержку. |
| 409 | На этом телефоне уже три аккаунта в этом приложении Telegram. Добавь аккаунт на другой телефон. |
| 409 | Телефон отключён от кабинета. Подключи его заново и повтори. |
Изменить аккаунт
PATCH /accounts/ID_АККАУНТА · право ключа: чтение и действия
Меняет название, лимиты и паузы аккаунта или выключает его. Передавай только то, что меняешь. Новые лимиты действуют сразу для сообщений, которые телефон ещё не взял.
| Поле | Где | Что это |
|---|---|---|
label | в теле | строка. Название аккаунта, 1–100 знаков. |
enabled | в теле | да/нет. false выключает аккаунт: он перестаёт отправлять. |
messageLimit | в теле | число. Сколько сообщений в сутки отправляет аккаунт, 0–100. |
phoneSearchLimit | в теле | число. Сколько получателей в сутки искать по номеру телефона, 0–15. |
taskDelayMin | в теле | число. Пауза между сообщениями, от: 0–86 400 с. Не больше taskDelayMax. |
taskDelayMax | в теле | число. Пауза между сообщениями, до: 0–86 400 с. |
accountDelayMin | в теле | число. Пауза при смене аккаунта, от: 0–86 400 с. Не больше accountDelayMax. |
accountDelayMax | в теле | число. Пауза при смене аккаунта, до: 0–86 400 с. |
searchDelayMin | в теле | число. Пауза перед поиском по номеру, от: 0–86 400 с. Не больше searchDelayMax. |
searchDelayMax | в теле | число. Пауза перед поиском по номеру, до: 0–86 400 с. |
curl -X PATCH "https://app.kelvintg.ru/api/v1/accounts/ID_АККАУНТА" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"messageLimit": 40
}'Ответ:
{
"id": "ID",
"deviceId": "ID",
"label": "Анна",
"phone": "+12025550401",
"enabled": true,
"deletedAt": null,
"messageLimit": 40,
"effectiveMessageLimit": 40,
"phoneSearchLimit": 15,
"taskDelayMin": 6,
"taskDelayMax": 6,
"accountDelayMin": 0,
"accountDelayMax": 0,
"searchDelayMin": 0
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Номер аккаунта изменить нельзя. Добавь новый аккаунт с другим номером. |
Прогрев и группы
Прогрев: план и факт на сегодня
GET /warmup/today · право ключа: только чтение
Отдаёт по каждому телефону и аккаунту, сколько заходов в Telegram запланировано на сегодня и сколько уже сделано. Сутки считаются по Москве.
curl "https://app.kelvintg.ru/api/v1/warmup/today" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"generatedAt": "2026-10-10T10:00:00.000Z",
"day": {
"from": "2026-10-09T21:00:00.000Z",
"to": "2026-10-10T21:00:00.000Z",
"timeZone": "Europe/Moscow"
},
"activePrograms": 0,
"workStopped": false,
"phones": [],
"summary": {
"planned": 0,
"completed": 0,
"running": 0,
"waiting": 0,
"interrupted": 0,
"needsReview": 0,
"skipped": 0,
"skippedReasons": [],
"manualInterventions": {
"decisions": 0,
"workStops": 0,
"workResumes": 0,
"warmupStops": 0,
"warmupResumes": 0,
"total": 0
},
"screenConflicts": null
}
}Прогрев: каналы и подписки
GET /warmup/sources · право ключа: только чтение
Отдаёт, сколько каналов есть в каталоге прогрева и чем закончились сегодняшние подписки: подписались, уже были подписаны, канал недоступен.
curl "https://app.kelvintg.ru/api/v1/warmup/sources" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"generatedAt": "2026-10-10T10:00:00.000Z",
"day": {
"from": "2026-10-09T21:00:00.000Z",
"to": "2026-10-10T21:00:00.000Z",
"timeZone": "Europe/Moscow"
},
"catalog": {
"approved": 621,
"pending": 0,
"rejected": 0,
"approvedByCategory": {
"large": 140,
"lending": 14,
"microblog": 223,
"hobby": 127,
"daily_life": 117
}
},
"joinsToday": {
"joined": 0,
"alreadyMember": 0,
"unavailable": 0,
"unknown": 0,
"inProgress": 0,
"total": 0
},
"unknownToday": [],
"noJoinProfiles": [
"read_only",
"… ещё 1"
]
}Список программ прогрева
GET /warmup-runs · право ключа: только чтение
Отдаёт программы прогрева кабинета, до 100, новые сверху: аккаунты, срок, часы работы и сколько заходов сделано.
curl "https://app.kelvintg.ru/api/v1/warmup-runs" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"runs": []
}Журнал программы прогрева
GET /warmup-runs/ID_ПРОГРЕВА/journal · право ключа: только чтение
Отдаёт, что происходило в программе, свежее сверху: заходы, подписки, остановки и их причины.
| Поле | Где | Что это |
|---|---|---|
accountId | в адресе | строка. Только записи этого аккаунта программы. |
limit | в адресе | число. Сколько записей отдать, 1–500. По умолчанию 100. |
curl "https://app.kelvintg.ru/api/v1/warmup-runs/ID_ПРОГРЕВА/journal?limit=50" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"items": []
}Журнал активности в группах
GET /group-activity/journal · право ключа: только чтение
Отдаёт отчёты телефона о заходах в группы для одного аккаунта, свежие сверху: что сделал и чем закончилось.
| Поле | Где | Что это |
|---|---|---|
accountId — обязательно | в адресе | строка. Аккаунт, чей журнал нужен. |
limit | в адресе | число. Сколько записей отдать, 1–500. По умолчанию 100. |
curl "https://app.kelvintg.ru/api/v1/group-activity/journal?accountId=$account&limit=50" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"reports": []
}Включить или выключить прогрев аккаунта
POST /accounts/ID_АККАУНТА/warmup · право ключа: чтение и действия
Включает или выключает простой прогрев одного аккаунта. Пока прогрев идёт, рассылка с этого аккаунта запустится только с подтверждением stopWarmup.
| Поле | Где | Что это |
|---|---|---|
action — обязательно | в теле | строка. "start" — включить, "stop" — выключить. |
curl -X POST "https://app.kelvintg.ru/api/v1/accounts/ID_АККАУНТА/warmup" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "stop"
}'Ответ:
{
"id": "ID",
"deviceId": "ID",
"client": {
"clientId": "tc_54b5fd93b04f5adf10d891521ec615bb",
"deviceId": "ID",
"kind": "default",
"userSerial": null,
"package": null,
"profileEpoch": null,
"installEpoch": null,
"bindingId": "tb_2285326d919db59459a0b11ebb35de15",
"bindingRevision": 1,
"legacyUnknown": true
},
"label": "Анна",
"phone": "+12025550401",
"enabled": true,
"deletedAt": null,
"messageLimit": 40,
"effectiveMessageLimit": 40,
"phoneSearchLimit": 15,
"taskDelayMin": 6,
"taskDelayMax": 6,
"accountDelayMin": 0,
"accountDelayMax": 0
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Аккаунт прямо сейчас отправляет сообщение. Включи прогрев, когда отправка закончится. |
Настроить активность в группах
PATCH /accounts/ID_АККАУНТА/group-activity · право ключа: чтение и действия
Настраивает, как аккаунт ведёт себя в группах и каналах: заходит, листает, ставит реакции, вступает. Передавай только то, что меняешь. Если включить, аккаунт начнёт делать это в Telegram по-настоящему.
| Поле | Где | Что это |
|---|---|---|
enabled | в теле | да/нет. Включить активность. Не включится, пока нет ни одной группы и выключен каталог. |
joinAllowed | в теле | да/нет. Можно ли вступать в группы. |
reactionsEnabled | в теле | да/нет. Ставить ли реакции. |
catalogEnabled | в теле | да/нет. Брать ли каналы из общего каталога KELVIN. |
groups | в теле | список строк. Разрешённые группы: @username или ссылка https://t.me/…, до 50. |
schedule | в теле | объект. Когда можно отправлять: {timeZone: "Europe/Moscow" или "UTC", startLocal: "ГГГГ-ММ-ДДTЧЧ:ММ" (не раньше текущей минуты) или null, weekdays: дни недели 0–6, где 0 — воскресенье, intervals: от 1 до 4 отрезков {start: "ЧЧ:ММ", end: "ЧЧ:ММ"}}. Если конец раньше начала, отрезок переходит через полночь. |
joinLimit24h | в теле | число. Вступлений в сутки, 0–50. По умолчанию 3. |
reactionLimit24h | в теле | число. Реакций в сутки, 0–300. По умолчанию 40. |
scrollMin | в теле | число. Сколько раз листать за заход, от: 0–100. По умолчанию 6. |
scrollMax | в теле | число. Сколько раз листать за заход, до: 0–100, не меньше scrollMin. По умолчанию 12. |
sessionMinSeconds | в теле | число. Длина захода, от: 30–3600 с. По умолчанию 90. |
sessionMaxSeconds | в теле | число. Длина захода, до: 30–3600 с, не меньше sessionMinSeconds. По умолчанию 180. |
pauseMinSeconds | в теле | число. Пауза между заходами, от: 0–86 400 с. По умолчанию 600. |
pauseMaxSeconds | в теле | число. Пауза между заходами, до: 0–86 400 с, не меньше pauseMinSeconds. По умолчанию 1800. |
maxActionsPerSession | в теле | число. Действий за заход, 1–20. По умолчанию 2. |
reactionEmojis | в теле | список строк. Какие реакции ставить: до 12 обычных бесплатных реакций Telegram. |
reactionProbability | в теле | число. Как часто ставить реакцию, от 0 до 1. По умолчанию 0.5. |
catalogPoolSize | в теле | число. Сколько каналов брать из каталога, 1–200. По умолчанию 40. |
sessionsLimit | в теле | число. Сколько заходов сделать всего, 0–1000. 0 — без ограничения. Новое значение обнуляет счётчик сделанных. |
channelsPerSession | в теле | число. Каналов за заход, 1–20. По умолчанию 1. |
curl -X PATCH "https://app.kelvintg.ru/api/v1/accounts/ID_АККАУНТА/group-activity" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"joinLimit24h": 2,
"reactionsEnabled": false
}'Ответ:
{
"settings": {
"configured": true,
"enabled": false,
"joinAllowed": false,
"reactionsEnabled": false,
"groups": [],
"schedule": null,
"joinLimit24h": 2,
"reactionLimit24h": 40,
"scrollMin": 6,
"scrollMax": 12,
"sessionMinSeconds": 90,
"sessionMaxSeconds": 180,
"pauseMinSeconds": 600,
"pauseMaxSeconds": 1800
},
"counters": {
"joins24h": 0,
"joinAttempts24h": 0,
"reactions24h": 0
},
"catalog": {
"enabled": false,
"poolSize": 40,
"size": 385,
"tracked": 0,
"actionable": 0,
"categories": {
"news": {
"size": 52,
"available": 0
},
"finance": {
"size": 20,
"available": 0| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Телефон прямо сейчас выполняет заход по группам. Дождись отчёта и повтори. |
| 400 | Включить нельзя: добавь хотя бы одну группу или включи каталог. |
Отметить, состоит ли аккаунт в группе
POST /accounts/ID_АККАУНТА/group-activity/group-state · право ключа: чтение и действия
Записывает твоё решение по группе из списка аккаунта: состоит он в ней, не состоит или группа недоступна. Нужен, когда телефон сам этого не понял. Заходы в эту группу, которые ждали в очереди, снимаются.
| Поле | Где | Что это |
|---|---|---|
group — обязательно | в теле | строка. Группа из списка этого аккаунта: @username или ссылка https://t.me/…. |
membership — обязательно | в теле | строка. "member" — состоит, "not_member" — не состоит, "unavailable" — группа недоступна, "unknown" — неизвестно. |
curl -X POST "https://app.kelvintg.ru/api/v1/accounts/ID_АККАУНТА/group-activity/group-state" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"group": "@synthetic_group",
"membership": "member"
}'Ответ:
{
"settings": {
"configured": true,
"enabled": false,
"joinAllowed": false,
"reactionsEnabled": false,
"groups": [
{
"kind": "username",
"value": "synthetic_group"
}
],
"schedule": null,
"joinLimit24h": 2,
"reactionLimit24h": 40,
"scrollMin": 6,
"scrollMax": 12,
"sessionMinSeconds": 90,
"sessionMaxSeconds": 180,
"pauseMinSeconds": 600,
"pauseMaxSeconds": 1800
},
"counters": {
"joins24h": 0,
"joinAttempts24h": 0,
"reactions24h": 0
},
"catalog": {
"enabled": false,
"poolSize": 40,
"size": 385,
"tracked": 0,
"actionable": 0,
"categories": {
"news": {
"size": 52,| Отказ | Что случилось и что сделать |
|---|---|
| 404 | Этой группы нет в списке аккаунта. Сначала добавь её в настройках активности в группах. |
Создать программу прогрева
POST /warmup-runs · право ключа: чтение и действия · нужен номер запроса
Создаёт черновик программы: какие аккаунты, сколько дней и в какие часы телефон читает каналы и подписывается на них. Прогрев не начинается, пока ты не вызовешь «Запустить программу прогрева».
| Поле | Где | Что это |
|---|---|---|
window — обязательно | в теле | объект. Часы, в которые телефон заходит в Telegram, каждый день: {timeZone: "Europe/Moscow" или "UTC", start: "ЧЧ:ММ", end: "ЧЧ:ММ"}. Если конец раньше начала, окно переходит через полночь. Окно должно быть длиннее одного захода. |
accounts — обязательно | в теле | список объектов. От 1 до 50 аккаунтов без повторов, каждый как {accountId, profile, durationDays, settings}. profile: "read_only" — только чтение, 1 заход в день; "work_reading" — чтение, 3–7 заходов; "safe" — 1–3 захода и 2–3 подписки; "standard" — 3–6 заходов и 5 подписок; "intensive" — 5–8 заходов и 7–8 подписок; "pilot_one" — одна пробная подписка. durationDays: 1–365. settings (только для read_only и work_reading): {visits: [от, до] в пределах 1–12, visitSeconds: [от, до] в пределах 60–600}. |
pilotHandle | в теле | строка. Только для profile "pilot_one": username канала из каталога, 5–32 знака. Тогда в программе один аккаунт и один день. |
start | в теле | да/нет. true — сразу проверить, что аккаунты свободны и телефоны умеют прогрев. Запуск всё равно отдельным запросом. |
curl -X POST "https://app.kelvintg.ru/api/v1/warmup-runs" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Idempotency-Key: order-0001" \
-H "Content-Type: application/json" \
-d '{
"window": {
"timeZone": "Europe/Moscow",
"start": "10:00",
"end": "20:00"
},
"accounts": [
{
"accountId": "ID_АККАУНТА",
"profile": "read_only",
"durationDays": 3
}
]
}'Ответ:
{
"outcome": "draft",
"id": "ID",
"status": "draft",
"window": {
"timeZone": "Europe/Moscow",
"start": "10:00",
"end": "20:00"
},
"accounts": [
{
"accountId": "ID",
"label": "Анна",
"profile": "read_only",
"durationDays": 3,
"newSubscriptionsConfirmed": 0,
"status": "draft",
"pilotHandle": null,
"settings": null,
"sessions": {
"total": 0,
"pending": 0,
"claimed": 0,
"completed": 0,
"skipped": 0,
"interrupted": 0,
"needsReview": 0,
"stopRequested": 0,
"nextScheduledAt": null,
"plannedDays": 0,
"nextReason": null,
"nextMaxSeconds": null
},
"categories": {},
"reading": {
"scrolls": 0,| Отказ | Что случилось и что сделать |
|---|---|
| 400 | Окно слишком короткое для выбранного режима. Раздвинь часы работы. |
Запустить программу прогрева
POST /warmup-runs/ID_ПРОГРЕВА/start · право ключа: чтение и действия
Запускает черновик программы: телефоны начнут заходить в Telegram в заданные часы. Если в кабинете нажато «Остановить всё», заходы начнутся после возобновления работы человеком.
curl -X POST "https://app.kelvintg.ru/api/v1/warmup-runs/ID_ПРОГРЕВА/start" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{}'Ответ:
{
"outcome": "running",
"id": "ID",
"status": "running",
"window": {
"timeZone": "Europe/Moscow",
"start": "10:00",
"end": "20:00"
},
"accounts": [
{
"accountId": "ID",
"label": "Анна",
"profile": "read_only",
"durationDays": 3,
"newSubscriptionsConfirmed": 0,
"status": "running",
"pilotHandle": null,
"settings": null,
"sessions": {
"total": 1,
"pending": 1,
"claimed": 0,
"completed": 0,
"skipped": 0,
"interrupted": 0,
"needsReview": 0,
"stopRequested": 0,
"nextScheduledAt": "2026-10-10T10:00:00.000Z",
"plannedDays": 1,
"nextReason": null,
"nextMaxSeconds": 120
},
"categories": {},
"reading": {
"scrolls": 0,| Отказ | Что случилось и что сделать |
|---|---|
| 409 | На телефоне старая версия KELVIN TG, она не умеет прогрев. Обнови приложение на каждом телефоне программы. |
| 409 | Аккаунт уже занят в другой запущенной программе. Останови её или убери аккаунт. |
| 409 | Программа остановлена или завершена. Остановленную продолжают запросом «Продолжить программу прогрева». |
Продолжить программу прогрева
POST /warmup-runs/ID_ПРОГРЕВА/resume · право ключа: чтение и действия
Продолжает остановленную программу или один остановленный аккаунт в ней. Оставшиеся заходы переносятся в новое окно. К кнопке «Возобновить работу» после «Остановить всё» этот запрос отношения не имеет.
| Поле | Где | Что это |
|---|---|---|
durationDays — обязательно | в теле | число. Сколько дней программа длится всего, 1–365. Не меньше, чем уже запланировано. |
window | в теле | объект. Часы, в которые телефон заходит в Telegram, каждый день: {timeZone: "Europe/Moscow" или "UTC", start: "ЧЧ:ММ", end: "ЧЧ:ММ"}. Если конец раньше начала, окно переходит через полночь. Обязательно, если продолжаешь всю остановленную программу. |
accountId | в теле | строка. Продолжить только этот аккаунт. Часы работы тогда остаются прежними. |
curl -X POST "https://app.kelvintg.ru/api/v1/warmup-runs/ID_ПРОГРЕВА/resume" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"durationDays": 3,
"window": {
"timeZone": "Europe/Moscow",
"start": "10:00",
"end": "20:00"
}
}'Ответ:
{
"outcome": "running",
"id": "ID",
"status": "running",
"window": {
"timeZone": "Europe/Moscow",
"start": "10:00",
"end": "20:00"
},
"accounts": [
{
"accountId": "ID",
"label": "Анна",
"profile": "read_only",
"durationDays": 3,
"newSubscriptionsConfirmed": 0,
"status": "running",
"pilotHandle": null,
"settings": null,
"sessions": {
"total": 1,
"pending": 1,
"claimed": 0,
"completed": 0,
"skipped": 0,
"interrupted": 0,
"needsReview": 0,
"stopRequested": 0,
"nextScheduledAt": "2026-10-10T10:00:00.000Z",
"plannedDays": 1,
"nextReason": null,
"nextMaxSeconds": 120
},
"categories": {},
"reading": {
"scrolls": 0,| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Телефон ещё не отчитался о заходе, который взял. Подожди отчёта и повтори. |
| 409 | Продолжать нечего: все заходы программы уже сделаны. |
| 400 | Срок меньше, чем дней уже запланировано. Увеличь durationDays. |
Остановить программу прогрева
POST /warmup-runs/ID_ПРОГРЕВА/stop · право ключа: чтение и действия
Останавливает программу для всех её аккаунтов. Заход, который телефон уже начал, он закончит и отчитается. Продолжить можно запросом «Продолжить программу прогрева».
curl -X POST "https://app.kelvintg.ru/api/v1/warmup-runs/ID_ПРОГРЕВА/stop" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{}'Ответ:
{
"outcome": "stopped",
"id": "ID",
"status": "stopped",
"window": {
"timeZone": "Europe/Moscow",
"start": "10:00",
"end": "20:00"
},
"accounts": [
{
"accountId": "ID",
"label": "Анна",
"profile": "read_only",
"durationDays": 3,
"newSubscriptionsConfirmed": 0,
"status": "stopped",
"pilotHandle": null,
"settings": null,
"sessions": {
"total": 1,
"pending": 0,
"claimed": 0,
"completed": 0,
"skipped": 1,
"interrupted": 0,
"needsReview": 0,
"stopRequested": 0,
"nextScheduledAt": null,
"plannedDays": 1,
"nextReason": null,
"nextMaxSeconds": null
},
"categories": {},
"reading": {
"scrolls": 0,Остановить прогрев одного аккаунта
POST /warmup-runs/ID_ПРОГРЕВА/accounts/ID_АККАУНТА/stop · право ключа: чтение и действия
Останавливает прогрев одного аккаунта, остальные в программе продолжают. Когда остановлены все аккаунты, останавливается и программа.
curl -X POST "https://app.kelvintg.ru/api/v1/warmup-runs/ID_ПРОГРЕВА/accounts/ID_АККАУНТА/stop" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{}'Ответ:
{
"outcome": "stopped",
"id": "ID",
"status": "stopped",
"window": {
"timeZone": "Europe/Moscow",
"start": "10:00",
"end": "20:00"
},
"accounts": [
{
"accountId": "ID",
"label": "Анна",
"profile": "read_only",
"durationDays": 3,
"newSubscriptionsConfirmed": 0,
"status": "stopped",
"pilotHandle": null,
"settings": null,
"sessions": {
"total": 1,
"pending": 0,
"claimed": 0,
"completed": 0,
"skipped": 1,
"interrupted": 0,
"needsReview": 0,
"stopRequested": 0,
"nextScheduledAt": null,
"plannedDays": 1,
"nextReason": null,
"nextMaxSeconds": null
},
"categories": {},
"reading": {
"scrolls": 0,Удалить черновик прогрева
DELETE /warmup-runs/ID_ПРОГРЕВА · право ключа: чтение и действия
Удаляет программу, которую ещё не запускали. Вернуть её нельзя. Запущенную программу удалить нельзя, её можно только остановить: она остаётся в истории.
curl -X DELETE "https://app.kelvintg.ru/api/v1/warmup-runs/ID_ПРОГРЕВА" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"ok": true,
"id": "ID"
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Программу уже запускали. Её можно остановить, но не удалить. |
Статистика и журнал
Статистика
GET /stats · право ключа: только чтение
Отдаёт то же, что страница «Статистика»: сколько отправлено, прочитано и сколько ответили, по аккаунтам, рассылкам и базам. Сообщения в состоянии «вероятно отправлено» считаются отправленными. Пустое значение вместо числа значит, что данных нет.
| Поле | Где | Что это |
|---|---|---|
days | в адресе | строка. Период: "7", "30" (по умолчанию) или "all" — за всё время. Сутки считаются по Москве. |
curl "https://app.kelvintg.ru/api/v1/stats?days=7" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"generatedAt": "2026-10-10T10:00:00.000Z",
"days": "7",
"since": "2026-10-03T21:00:00.000Z",
"accountPrice": null,
"lowDataBelow": 30,
"summary": {
"sent": 0,
"unknown": 0,
"read": null,
"replied": null,
"replyRate": null,
"repliesKnown": false,
"tracked": 0,
"lowData": true,
"accounts": 0,
"spent": null,
"costPerMessage": null,
"costPerReply": null,
"visualEnabled": false,
"visualEligibleChats": 0
},
"campaigns": [],
"bases": [],
"accounts": [
{
"id": "ID",
"label": "Анна",
"deviceName": "Телефон 1",
"status": "working",
"days": 1,
"firstSentAt": null,
"sent": 0,
"unknown": 0,
"read": null,
"replied": null,Отправки по аккаунтам
GET /stats/accounts · право ключа: только чтение
Отдаёт по каждому аккаунту, сколько сообщений рассылок он отправил всего, за 7 дней и сегодня, сколько лидов ответили и когда была последняя отправка.
curl "https://app.kelvintg.ru/api/v1/stats/accounts" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"generatedAt": "2026-10-10T10:00:00.000Z",
"accounts": [
{
"id": "ID",
"label": "Анна",
"deviceName": "Телефон 1",
"deleted": false,
"total": 0,
"week": 0,
"today": 0,
"replies": 0,
"lastAt": null
}
]
}Итог за 7 дней
GET /today/week · право ключа: только чтение
Отдаёт по дням за последнюю неделю: сколько отправлено, сколько сообщений ждут проверки, сколько аккаунтов получили ограничение и сколько раз работу останавливали. Сутки считаются по Москве.
curl "https://app.kelvintg.ru/api/v1/today/week" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"generatedAt": "2026-10-10T10:00:00.000Z",
"timeZone": "Europe/Moscow",
"days": [
{
"date": "2026-10-04",
"total": null,
"sent": null,
"unknown": null,
"needsReview": null,
"decisions": null,
"restrictedAccounts": null,
"workStops": null
},
"… ещё 6"
],
"current": {
"from": "2026-10-04",
"to": "2026-10-10",
"total": null,
"sent": null,
"unknown": null,
"needsReview": null,
"decisions": null,
"restrictedAccounts": null,
"workStops": null
},
"previous": {
"from": "2026-09-27",
"to": "2026-10-03",
"total": null,
"sent": null,
"unknown": null,
"needsReview": null,
"decisions": null,
"restrictedAccounts": null,Сколько ещё уйдёт сегодня
GET /day-plan · право ключа: только чтение
Оценивает по каждому телефону, сколько сообщений он ещё может отправить до конца суток по Москве, и называет причины, если отправка стоит. Это оценка «от и до» по лимитам и времени, а не обещание.
curl "https://app.kelvintg.ru/api/v1/day-plan" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"generatedAt": "2026-10-10T10:00:00.000Z",
"moscowDayEndsAt": "2026-10-10T21:00:00.000Z",
"stopActive": false,
"phones": [
{
"deviceId": "ID",
"deviceName": "Телефон 1",
"noData": true,
"range": null,
"reasons": [
{
"code": "device_offline",
"title": "Телефон не на связи"
},
"… ещё 1"
],
"accounts": [
{
"accountId": "ID",
"label": "Анна",
"remainingToday": 80,
"reasons": []
}
],
"campaigns": []
}
]
}Журнал событий
GET /events · право ключа: только чтение
Отдаёт журнал кабинета, свежее сверху: кто что сделал и когда. У действий, сделанных программой, указано название ключа. Тексты записей частично на английском, поэтому в программе опирайся на поле type.
| Поле | Где | Что это |
|---|---|---|
from | в адресе | строка. С какого момента, включительно. Дата и время в виде 2026-10-10T09:00:00.000Z. |
to | в адресе | строка. До какого момента, не включая его. В том же виде. |
accountId | в адресе | строка. Только события этого аккаунта. |
deviceId | в адресе | строка. Только события этого телефона и его аккаунтов. |
type | в адресе | строка. Типы событий через запятую, до 50. Например campaign_created,work_stopped. |
before | в адресе | строка. Значение nextBefore из прошлого ответа: придёт следующая, более старая страница. |
limit | в адресе | число. Сколько записей отдать, 1–200. По умолчанию 50. |
curl "https://app.kelvintg.ru/api/v1/events?limit=20" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"items": [
{
"id": "ID",
"at": "2026-10-10T10:00:00.000Z",
"type": "campaign_playbook_created",
"message": "Набор «Первое касание» сохранён",
"accountId": null,
"deviceId": null,
"objectId": "ID",
"outcome": "ok",
"actor": "operator",
"by": "demo",
"apiKey": "Пример",
"before": null,
"after": null
},
"… ещё 11"
],
"nextBefore": null
}«Остановить всё»
Нажато ли «Остановить всё»
GET /work/stop-all · право ключа: только чтение
Отвечает, остановлена ли работа кабинета, кто и когда её остановил и как каждый телефон это подтвердил. Пока работа остановлена, телефоны новых заданий не получают.
curl "https://app.kelvintg.ru/api/v1/work/stop-all" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"stopped": false,
"stoppedAt": null,
"stoppedBy": null,
"devices": [],
"resumable": null
}Остановить всё
POST /work/stop-all · право ключа: чтение и действия
Сразу останавливает всю работу кабинета: рассылки, прогрев и активность в группах. Сообщение, которое телефон уже начал отправлять, он закончит. Программа может только остановить: возобновить работу может только человек в кабинете, кнопкой «Возобновить работу».
curl -X POST "https://app.kelvintg.ru/api/v1/work/stop-all" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{}'Ответ:
{
"stopped": true,
"stoppedAt": "2026-10-10T10:00:00.000Z",
"stoppedBy": "demo",
"devices": [
{
"id": "ID",
"name": "Телефон 1",
"state": "offline",
"reason": "no_heartbeat_since_stop",
"why": "Телефон не выходил на связь после остановки",
"activeWork": null,
"lastSeen": null
}
],
"resumable": {
"runningCampaigns": [
{
"id": "ID",
"name": "Проверка",
"pending": 1
}
],
"activeWarmupRuns": [],
"stoppedWarmupRuns": [],
"groupActivityAccounts": []
},
"alreadyStopped": false
}Опасные действия
Удалить аккаунт
DELETE /accounts/ID_АККАУНТА · право ключа: опасные действия
Убирает аккаунт из кабинета: его сообщения в очереди отменяются, и это не отменить. Из рассылок он выходит, а общую очередь получателей доделают другие аккаунты. Сам аккаунт в Telegram не трогается, история в статистике остаётся.
curl -X DELETE "https://app.kelvintg.ru/api/v1/accounts/ID_АККАУНТА" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"ok": true,
"alreadyDeleted": false
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Аккаунт прямо сейчас выполняет задание или проверку. Дождись конца и повтори. |
Отключить телефон
POST /devices/ID_ТЕЛЕФОНА/revoke · право ключа: опасные действия
Сразу отключает телефон от кабинета, например если он потерян. Сообщения его аккаунтов в очереди отменяются, и это не отменить. Вернуть телефон можно только новым подключением по коду с самого телефона.
| Поле | Где | Что это |
|---|---|---|
confirmed — обязательно | в теле | да/нет. Должно быть true: так ты подтверждаешь отключение. |
curl -X POST "https://app.kelvintg.ru/api/v1/devices/ID_ТЕЛЕФОНА/revoke" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"confirmed": true
}'Ответ:
{
"id": "ID",
"name": "Телефон 1",
"lastSeen": null,
"status": "offline",
"androidVersion": null,
"telegramVersion": null,
"accessibilityEnabled": false,
"keyboardEnabled": null,
"power": null,
"screenUnlocked": false,
"networkConnected": false,
"liveEnabled": false,
"manualScreen": false,
"networkGroup": null
}Удалить телефон
POST /devices/ID_ТЕЛЕФОНА/delete · право ключа: опасные действия
Отключает телефон, убирает его из списка и удаляет из кабинета все его аккаунты. Их сообщения в очереди отменяются, и это не отменить. История остаётся в журнале, а те же номера можно добавить заново на другом телефоне.
| Поле | Где | Что это |
|---|---|---|
confirmed — обязательно | в теле | да/нет. Должно быть true: так ты подтверждаешь удаление. |
curl -X POST "https://app.kelvintg.ru/api/v1/devices/ID_ТЕЛЕФОНА/delete" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"confirmed": true
}'Ответ:
{
"ok": true,
"alreadyDeleted": false,
"archivedAccounts": 1
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Телефон прямо сейчас выполняет задание. Дождись отчёта и повтори. |
Подтвердить, что сообщение ушло
POST /tasks/ID_ОТПРАВКИ/confirm-delivery · право ключа: опасные действия
Для сообщений в состоянии «вероятно отправлено»: ты сам посмотрел в Telegram и подтверждаешь, что оно доставлено. Сообщение навсегда записывается как отправленное и попадает в статистику, отменить это нельзя. Повторно KELVIN такое сообщение не отправляет в любом случае.
| Поле | Где | Что это |
|---|---|---|
confirmed — обязательно | в теле | да/нет. Должно быть true. |
manualSend | в теле | да/нет. true — если сообщение остановила пауза рассылки и ты отправил его руками в Telegram. |
curl -X POST "https://app.kelvintg.ru/api/v1/tasks/ID_ОТПРАВКИ/confirm-delivery" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"confirmed": true
}'Ответ:
{
"ok": true,
"alreadyConfirmed": false
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Подтвердить можно только сообщение с неясным итогом отправки. У этого итог уже известен. |
| 409 | Телефон этого аккаунта сейчас выполняет задание. Дождись конца и повтори. |
Оставить сообщение на проверке
POST /tasks/ID_ОТПРАВКИ/keep-review · право ключа: опасные действия
Записывает в журнал твоё решение: итог отправки этого сообщения пока неясен, разберёшься позже. Состояние сообщения и счётчики не меняются, но запись в журнале остаётся навсегда.
| Поле | Где | Что это |
|---|---|---|
note | в теле | строка. Заметка для себя, до 200 знаков. |
curl -X POST "https://app.kelvintg.ru/api/v1/tasks/ID_ОТПРАВКИ/keep-review" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"note": "Проверю позже"
}'Ответ:
{
"ok": true,
"alreadyRecorded": false
}| Отказ | Что случилось и что сделать |
|---|---|
| 409 | У этого сообщения итог уже известен или доставка подтверждена. Оставлять на проверке нечего. |
Проверка @SpamBot: включить или выключить
POST /accounts/ID_АККАУНТА/health/gate · право ключа: опасные действия
Включает или выключает для аккаунта проверку у @SpamBot. Если включить, аккаунт перед следующей серией сообщений спросит @SpamBot и будет отправлять только при ответе «ограничений нет». Если выключить, аккаунт пишет без этой проверки, и ограничение от Telegram ты заметишь позже.
| Поле | Где | Что это |
|---|---|---|
enabled — обязательно | в теле | да/нет. true — включить проверку, false — выключить. |
curl -X POST "https://app.kelvintg.ru/api/v1/accounts/ID_АККАУНТА/health/gate" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled": true
}'Ответ:
{
"id": "ID",
"deviceId": "ID",
"client": {
"clientId": "tc_54b5fd93b04f5adf10d891521ec615bb",
"deviceId": "ID",
"kind": "default",
"userSerial": null,
"package": null,
"profileEpoch": null,
"installEpoch": null,
"bindingId": "tb_2285326d919db59459a0b11ebb35de15",
"bindingRevision": 1,
"legacyUnknown": true
},
"label": "Анна",
"phone": "+12025550401",
"enabled": true,
"deletedAt": null,
"messageLimit": 40,
"effectiveMessageLimit": 40,
"phoneSearchLimit": 15,
"taskDelayMin": 6,
"taskDelayMax": 6,
"accountDelayMin": 0,
"accountDelayMax": 0
}Снять остановку после @SpamBot
POST /accounts/ID_АККАУНТА/health/clear · право ключа: опасные действия
Вручную возвращает аккаунт в работу, не спрашивая @SpamBot: отправка с него продолжится. Если ограничение в Telegram на самом деле не снято, сообщения уйдут с ограниченного аккаунта, и вернуть их нельзя. Пока идут 12 часов после ответа @SpamBot об ограничении, запрос откажет.
| Поле | Где | Что это |
|---|---|---|
confirmed — обязательно | в теле | да/нет. Должно быть true. |
curl -X POST "https://app.kelvintg.ru/api/v1/accounts/ID_АККАУНТА/health/clear" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"confirmed": true
}'| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Аккаунт отложен на 12 часов после ограничения от @SpamBot. Раньше этого срока остановку снять нельзя, срок указан в ответе. |
| 409 | Снимать нечего: аккаунт не ждёт проверки и не остановлен. |
Проверить аккаунт у @SpamBot снова
POST /accounts/ID_АККАУНТА/health/recheck · право ключа: опасные действия
Просит телефон заново спросить @SpamBot. Аккаунт вернётся к отправке, только если придёт ответ «ограничений нет». Проверку делает телефон, когда до неё дойдёт очередь, и отозвать её нельзя.
curl -X POST "https://app.kelvintg.ru/api/v1/accounts/ID_АККАУНТА/health/recheck" \
-H "Authorization: Bearer $KELVIN_KEY" \
-H "Content-Type: application/json" \
-d '{}'| Отказ | Что случилось и что сделать |
|---|---|
| 409 | Проверить снова можно, только когда проверка @SpamBot включена и отправка с аккаунта остановлена после неё. |
| 409 | Аккаунт отложен на 12 часов после ограничения от @SpamBot. Повтори после срока из ответа. |
Скачать данные кабинета
GET /workspace/export · право ключа: опасные действия
Отдаёт одним файлом рассылки, получателей, аккаунты, телефоны и журнал всего кабинета. Паролей, ключей и текстов переписки в файле нет, но списки получателей есть: файл, который ушёл наружу, обратно не вернуть. Скачивание записывается в журнал. Файл может быть большим.
curl "https://app.kelvintg.ru/api/v1/workspace/export" \
-H "Authorization: Bearer $KELVIN_KEY"Ответ:
{
"exportedAt": "2026-10-10T10:00:00.000Z",
"workspaceId": "ID",
"campaigns": [
{
"id": "ID",
"name": "Проверка",
"baseLabel": null,
"status": "pending",
"createdAt": "2026-10-10T10:00:00.000Z",
"schedule": null,
"scheduleStatus": null,
"editable": true,
"revision": 1,
"startedAt": null,
"secondTouch": {
"enabled": false,
"waiting": false,
"planned": 0,
"sent": 0
},
"post": null,
"autoReply": {
"enabled": false,
"sent": 0,
"waiting": 0,
"refused": 0,
"missed": 0
},
"total": 1
},
"… ещё 13"
],
"tasks": [
{
"id": "ID",