Аттрибуты пользователей

Кастомные поля пользователя: город, источник, отказ от рассылки и любые свои ключи.

Два слоя:

  1. Справочник ключей бота — какие атрибуты есть у бота и как они называются.
  2. Значения пользователя — что записано конкретному пользователю.

Авторизация

Все методы — POST с телом JSON.

ПараметрГдеОбязательностьОписание
bot_idтелодаID бота в BOT-T
token или botTokenquery или телода*Токен бота
secretKeyqueryда*Секретный ключ бота (альтернатива токену)

* Достаточно либо token/botToken, либо secretKey.

Заголовки:

Content-Type: application/json

Базовый URL:

https://api.bot-t.com

Формат ответа:

{ "result": true, "data": ... }
{ "result": false, "message": "текст ошибки" }

Всегда проверяйте result === true перед использованием data.

Лимит запросов: 120 запросов в минуту с одного IP.


Как устроены атрибуты

Атрибут — пара keyvalue (строки). Это отдельные поля, не статус и не баланс пользователя.

ТипПримеры ключей
Кастомныеcity, source, любой свой ключ
Системныеmailing_opt_out, utm, utm_first

Правила ключа:

  • после записи ключ приводится к нижнему регистру (Citycity);
  • начинается с латинской буквы, дальше буквы, цифры или _, длина 1–32;
  • значение — строка до 1024 символов; null или пустая строка удаляет значение.

Запрещены: balance, status, expectation, referral.

Системные:

КлючМожно писать из APIОписание
mailing_opt_outдаотказ от рассылки; любое непустое значение сохраняется как "1"
utmнеттекущий UTM, задаётся автоматически
utm_firstнетпервый UTM, задаётся автоматически и не перезаписывается

Если записать кастомный ключ, которого ещё нет в справочнике, он создастся сам (название = ключ). Чтобы сразу задать своё название — сначала создайте ключ в справочнике.


Кто такой user_id

В методах значений нужен системный ID пользователя — поле user.id из ответа просмотра пользователя:

  • POST /v1/bot/user/view-by-telegram-id
  • POST /v1/bot/user/view-by-user-id
  • POST /v1/bot/user/view — берите user.id, не верхний id

Либо передайте telegram_id вместо user_id — достаточно одного из двух.

Верхний id из ответа пользователя (ID записи в боте) сюда не подходит.


Справочник ключей бота

МетодURLНазначение
indexPOST /v1/bot/user/attribute-def/indexсписок ключей бота
createPOST /v1/bot/user/attribute-def/createдобавить ключ
updatePOST /v1/bot/user/attribute-def/updateпереименовать (только title)
deletePOST /v1/bot/user/attribute-def/deleteудалить ключ из справочника

Системные ключи в справочник не входят.

POST /v1/bot/user/attribute-def/index

Тело: только bot_id.

{
  "result": true,
  "data": [
    { "id": 15, "bot_id": 1, "key": "city", "title": "Город" }
  ]
}

POST /v1/bot/user/attribute-def/create — добавить атрибут

ПолеТипОписание
bot_idintegerID бота
keystringключ (city)
titlestringназвание; если пусто — равно key
{
  "bot_id": 1,
  "key": "city",
  "title": "Город"
}

Ответ — созданный элемент справочника (id, bot_id, key, title).

Повторный запрос с тем же key вернёт уже существующую запись, ключ не дублируется.

POST /v1/bot/user/attribute-def/update — переименовать

Ключ (key) менять нельзя, только название.

ПолеТипОписание
bot_idintegerID бота
idintegerID записи справочника
titlestringновое название
{
  "bot_id": 1,
  "id": 15,
  "title": "Город проживания"
}

POST /v1/bot/user/attribute-def/delete — удалить атрибут из справочника

ПолеТипОписание
bot_idintegerID бота
idintegerID записи справочника
{
  "bot_id": 1,
  "id": 15
}
{ "result": true, "data": { "ok": true } }

Удаляется только справочник. Значения у пользователей остаются. Чтобы стереть значение — вызовите удаление значения.


Значения у пользователя

МетодURLНазначение
indexPOST /v1/bot/user/attribute/indexпрочитать все значения
upsertPOST /v1/bot/user/attribute/upsertдобавить или изменить
deletePOST /v1/bot/user/attribute/deleteудалить значение

Ответ этих трёх методов одинаковый:

{
  "result": true,
  "data": {
    "attributes": {
      "city": "Москва",
      "source": "ads"
    },
    "system_attributes": {
      "mailing_opt_out": "1"
    }
  }
}
ПолеОписание
attributesкастомные ключи
system_attributesmailing_opt_out, utm, utm_first (если заданы)

Пустых ключей в ответе нет. Те же поля приходят при просмотре одного пользователя (view, view-by-telegram-id, view-by-user-id). В списке пользователей их нет.

POST /v1/bot/user/attribute/index — прочитать

ПолеТипОписание
bot_idintegerID бота
user_idintegerсистемный ID пользователя или
telegram_idintegerTelegram ID
{
  "bot_id": 1,
  "telegram_id": 182352323552
}

POST /v1/bot/user/attribute/upsert — добавить или изменить

Один метод: нет ключа — создаст, есть — перезапишет.

ПолеТипОписание
bot_idintegerID бота
user_id или telegram_idintegerкто
keystringключ
valuestring или nullзначение; null или "" удаляет ключ

Добавить или изменить город:

{
  "bot_id": 1,
  "telegram_id": 182352323552,
  "key": "city",
  "value": "Москва"
}

Отписать от рассылки:

{
  "bot_id": 1,
  "telegram_id": 182352323552,
  "key": "mailing_opt_out",
  "value": "1"
}

Вернуть в рассылку — удалите ключ.

POST /v1/bot/user/attribute/delete — удалить значение

ПолеТипОписание
bot_idintegerID бота
user_id или telegram_idintegerкто
keystringкакой ключ
{
  "bot_id": 1,
  "telegram_id": 182352323552,
  "key": "city"
}

Если ключа у пользователя нет — запрос всё равно успешен, в ответе текущие значения без этого ключа.


Типичный сценарий

  1. Создать ключ city с названием «Город» (можно пропустить).
  2. Записать город пользователю.
  3. Прочитать значения.
  4. Записать новое значение — изменить.
  5. Удалить значение.
  6. Удалить ключ из справочника бота (значения у пользователей не трогает).

Примеры кода

API_BASE   = https://api.bot-t.com
BOT_ID     = 1
BOT_TOKEN  = 123456789:ABCdefGHI...

PHP

<?php

const API_BASE = 'https://api.bot-t.com';
const BOT_ID = 1;
const BOT_TOKEN = '123456789:ABCdefGHI...';

function botAttrRequest(string $path, array $body): array
{
    $url = API_BASE . '/v1/bot/user/' . $path . '?token=' . urlencode(BOT_TOKEN);

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
        CURLOPT_POSTFIELDS => json_encode(array_merge(['bot_id' => BOT_ID], $body)),
    ]);

    $response = curl_exec($ch);
    curl_close($ch);

    $data = json_decode($response, true);
    if (!is_array($data) || ($data['result'] ?? false) !== true) {
        throw new RuntimeException($data['message'] ?? 'API error');
    }

    return $data['data'];
}

// Справочник: добавить ключ
$def = botAttrRequest('attribute-def/create', [
    'key' => 'city',
    'title' => 'Город',
]);

// Значение: записать / изменить
$maps = botAttrRequest('attribute/upsert', [
    'telegram_id' => 182352323552,
    'key' => 'city',
    'value' => 'Москва',
]);

// Прочитать
$maps = botAttrRequest('attribute/index', [
    'telegram_id' => 182352323552,
]);

// Удалить значение
$maps = botAttrRequest('attribute/delete', [
    'telegram_id' => 182352323552,
    'key' => 'city',
]);

// Удалить ключ из справочника
botAttrRequest('attribute-def/delete', ['id' => $def['id']]);

JavaScript (Node.js, fetch)

const API_BASE = 'https://api.bot-t.com';
const BOT_ID = 1;
const BOT_TOKEN = '123456789:ABCdefGHI...';

async function botAttrRequest(path, body = {}) {
  const url = `${API_BASE}/v1/bot/user/${path}?token=${encodeURIComponent(BOT_TOKEN)}`;
  const response = await fetch(url, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ bot_id: BOT_ID, ...body }),
  });
  const json = await response.json();
  if (!json.result) {
    throw new Error(json.message || 'API error');
  }
  return json.data;
}

(async () => {
  const def = await botAttrRequest('attribute-def/create', {
    key: 'city',
    title: 'Город',
  });

  await botAttrRequest('attribute/upsert', {
    telegram_id: 182352323552,
    key: 'city',
    value: 'Москва',
  });

  const maps = await botAttrRequest('attribute/index', {
    telegram_id: 182352323552,
  });
  console.log(maps.attributes.city);

  await botAttrRequest('attribute/delete', {
    telegram_id: 182352323552,
    key: 'city',
  });

  await botAttrRequest('attribute-def/delete', { id: def.id });
})();

Токен бота не храните в браузерном JavaScript — вызывайте API с сервера.

Python 3

import requests

API_BASE = 'https://api.bot-t.com'
BOT_ID = 1
BOT_TOKEN = '123456789:ABCdefGHI...'


def bot_attr_request(path: str, body: dict = None) -> dict:
    url = f'{API_BASE}/v1/bot/user/{path}'
    payload = {'bot_id': BOT_ID, **(body or {})}
    response = requests.post(
        url,
        params={'token': BOT_TOKEN},
        json=payload,
        headers={'Content-Type': 'application/json'},
        timeout=30,
    )
    response.raise_for_status()
    data = response.json()
    if not data.get('result'):
        raise RuntimeError(data.get('message', 'API error'))
    return data['data']


# Справочник
def_ = bot_attr_request('attribute-def/create', {'key': 'city', 'title': 'Город'})

# Записать / изменить
bot_attr_request('attribute/upsert', {
    'telegram_id': 182352323552,
    'key': 'city',
    'value': 'Москва',
})

# Прочитать
maps = bot_attr_request('attribute/index', {'telegram_id': 182352323552})
print(maps['attributes'].get('city'))

# Удалить значение
bot_attr_request('attribute/delete', {
    'telegram_id': 182352323552,
    'key': 'city',
})

# Удалить ключ справочника
bot_attr_request('attribute-def/delete', {'id': def_['id']})

Типичные ошибки

СообщениеПричина
bot_id not foundНет bot_id в теле
token not found / token is not validНет или неверный токен
secretKey is not validНеверный secretKey
user_id not foundНет ни user_id, ни telegram_id
user not foundПользователь не найден в этом боте
key not foundНе передан key
id not foundНет id при изменении или удалении ключа справочника
Некорректный ключ атрибутаКлюч не подходит под формат
Этот ключ зарезервированbalance, status, expectation, referral
Системный атрибут нельзя изменить вручнуюПопытка записать utm или utm_first
Значение атрибута слишком длинноеБольше 1024 символов
Название атрибута не может быть пустымПустой title при создании или переименовании
Нет доступа к атрибутуКлюч справочника принадлежит другому боту

Важные замечания

  1. В этих методах user_id — системный ID (user.id из просмотра пользователя), не верхний id записи в боте. Проще передать telegram_id.
  2. Добавить и изменить значение — один метод upsert.
  3. Пустой value в upsert удаляет значение, как отдельное удаление.
  4. Удаление ключа из справочника не чистит значения пользователей.
  5. utm и utm_first из API только читаются.
  6. Авторизация через секретный ключ: POST /v1/bot/user/attribute/upsert?secretKey=YOUR_SECRET_KEY.