Процесс использования API модуля у товаров

API-модуль товара

Инструкция для интеграций, где товар формируется на вашем сервере, а не лежит на складе BOT-T.

Два сценария:

  1. После оплаты. BOT-T шлёт вебхук с заказом. Вы записываете содержимое и отправляете его покупателю.
  2. Через обратную связь. Покупатель заполняет форму. BOT-T шлёт заявку на ваш URL. Вы отвечаете текстом — BOT-T отправляет его в Telegram.

Сценарий 1. Оплата → вебхук → выдача

sequenceDiagram
    participant Buyer as Покупатель
    participant Bot as BOT-T
    participant You as Ваш сервер

    Buyer->>Bot: Оплачивает заказ
    Bot->>You: POST вебхук с объектом заказа
    You->>You: Готовите ключ / аккаунт / ссылку
    You->>Bot: POST update-product
    You->>Bot: POST send-product
    Bot->>Buyer: Содержимое в Telegram
  1. Покупатель оплачивает заказ.
  2. BOT-T отправляет на ваш URL объект заказа.
  3. Вы формируете содержимое.
  4. Записываете его в заказ: update-product.
  5. Отправляете покупателю: send-product.

Пока не вызваны оба метода, покупатель может не получить товар.

Подготовка в ЛК

У категории включите модуль API и укажите HTTPS URL «уведомление после оплаты».

Для обратных вызовов update-product и send-product нужен токен бота:

  • bot_id + botToken (или secretKey)

Запросы к API BOT-T выполняйте только с вашего backend.

Повторы вебхука возможны (до 3 попыток при сетевой ошибке). Обработка должна быть идемпотентной по id заказа: не выдавайте новый ключ на каждый повтор.

Что приходит на ваш URL

POST, тело application/x-www-form-urlencoded (не JSON).
В PHP это $_POST. Ответ: HTTP 2xx, тело не проверяется. Отвечайте быстро, тяжёлую работу уводите в очередь у себя.

Пример объекта заказа (в форме те же поля вложенно: category[id], user[telegram_id], product[data]):

{
  "id": 1001,
  "count": 1,
  "status": 1,
  "price": "150.00 ₽",
  "amount": 15000,
  "discount": 0,
  "created_at": "2024-05-21 12:00:00",
  "email": "[email protected]",
  "bot_clone_id": null,
  "purchase_bot_title": "—",
  "product": {
    "type": "text",
    "data": ""
  },
  "user": {
    "id": 100500,
    "telegram_id": 182352323552,
    "username": "buyer",
    "first_name": "Иван",
    "last_name": "Иванов",
    "link": "@buyer",
    "type": "private"
  },
  "botUser": {
    "id": 555,
    "bot_id": 1,
    "money": 0,
    "create_at": 1716280000,
    "created_time": "2024-05-21 10:00:00",
    "update_at": 1716280000,
    "updated_time": "2024-05-21 10:00:00",
    "expectation": null,
    "secret_user_key": null,
    "ref": null,
    "status": {
      "id": 1,
      "title": "Активен"
    },
    "user": {
      "id": 100500,
      "telegram_id": 182352323552,
      "username": "buyer",
      "first_name": "Иван",
      "last_name": "Иванов",
      "link": "@buyer",
      "type": "private"
    }
  },
  "category": {
    "id": 42,
    "category_id": null,
    "type": 1,
    "status": 1,
    "is_hide": false,
    "is_view": true,
    "api_id": 7,
    "feedback_id": null,
    "design": {
      "title": "Ключ на 30 дней",
      "description": "Описание до покупки",
      "instruction": "Инструкция после покупки"
    },
    "price": {
      "full": "150.00 ₽",
      "amount": 15000,
      "discount": 0,
      "old_price": 0
    }
  }
}
ПолеЗачем
idorder_id для update-product и send-product
status1 — оплачен. 0 — ещё не оплачен
amountСумма в копейках, уже со скидками BOT-T
countКоличество
product.dataТекущее содержимое. До вашего ответа часто пустое
user.telegram_idTelegram покупателя
botUser.idID пользователя в боте
category.id / category.design.titleКакой товар купили
emailEmail, если есть. Иначе null

Если к заказу уже привязана заявка обратной связи, в том же POST будет поле reviews. Формат — как объект заявки в сценарии 2.

Записать содержимое

POST https://api.bot-t.com/v1/shop/order/update-product?botToken=...

Заголовок: Content-Type: application/json

{
  "bot_id": 1,
  "order_id": 1001,
  "product": "KEY-ABC-123"
}

Несколько строк — через \n:

{
  "bot_id": 1,
  "order_id": 1001,
  "product": "login: user01\npassword: secret\nurl: https://example.com"
}
ПолеОбязательноОписание
bot_idдаID бота
order_idдаid из вебхука
productдаТекст до 9999 символов

Заказ должен быть оплачен. Метод только пишет product, в Telegram ничего не шлёт.

Успешный ответ:

{
  "result": true,
  "data": {
    "id": 1001,
    "category_id": 42,
    "count": 1,
    "bot_user_id": 555,
    "user_id": 100500,
    "telegram_id": 182352323552,
    "status": 1,
    "price": {
      "sum": "150.00 ₽",
      "balance_type_id": "Баланс",
      "currency": "RUB"
    },
    "product": "KEY-ABC-123",
    "created_at": 1716288000,
    "coupon": null
  }
}

Ошибка:

{
  "result": false,
  "message": "Нельзя изменить содержимое неоплаченного или отменённого заказа"
}

Отправить покупателю

POST https://api.bot-t.com/v1/shop/order/send-product?botToken=...

{
  "bot_id": 1,
  "order_id": 1001
}

Ответ — тот же объект заказа, что у update-product. Сначала update-product, потом send-product. Иначе уйдёт старое или пустое содержимое.

Пример обработчика

<?php

const BOT_ID = 1;
const BOT_TOKEN = '123456789:ABCdefGHI...';

$orderId = (int)($_POST['id'] ?? 0);
if ($orderId <= 0) {
    http_response_code(400);
    exit;
}

$product = 'KEY-' . $orderId;

botShopOrder('update-product', [
    'order_id' => $orderId,
    'product' => $product,
]);
botShopOrder('send-product', [
    'order_id' => $orderId,
]);

http_response_code(200);
echo 'OK';

function botShopOrder(string $action, array $body): array
{
    $url = 'https://api.bot-t.com/v1/shop/order/' . $action
        . '?botToken=' . 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)),
    ]);
    $raw = curl_exec($ch);
    curl_close($ch);
    $data = json_decode($raw, true);
    if (!is_array($data) || empty($data['result'])) {
        throw new RuntimeException($data['message'] ?? 'API error');
    }
    return $data['data'];
}

Сценарий 2. Обратная связь → ваш API → сообщение клиенту

Форма собирает данные у покупателя (логин, почту, выбор тарифа). Когда заявка заполнена, BOT-T сам вызывает ваш URL. Ответ вашего сервера BOT-T отправляет покупателю в чат.

Этот вызов не пишет товар в заказ. Если содержимое должно остаться в заказе и в кабинете — дополнительно вызовите update-product (и при необходимости send-product). order_id лежит в поле заявки data.

sequenceDiagram
    participant Buyer as Покупатель
    participant Bot as BOT-T
    participant You as Ваш сервер

    Buyer->>Bot: Заполняет форму обратной связи
    Bot->>You: POST заявка (интеграция CUSTOM)
    You->>You: Готовите товар по ответам
    You-->>Bot: JSON result + data.message
    Bot->>Buyer: Текст data.message в Telegram

Подготовка в ЛК

  1. Создайте сообщение обратной связи и вопросы (текст, выбор, файл).
  2. Привяжите его к товару: покупатель получает форму после оплаты.
  3. В обратной связи откройте интеграции и добавьте тип CUSTOM.
  4. В поле «Публичный ключ» укажите HTTPS URL вашего сервера.
    «Приватный ключ» и «Дополнительный ключ» для CUSTOM не используются — можно оставить пустыми, если интерфейс их требует.

Интеграция срабатывает один раз, когда покупатель ответил на все вопросы.

Что BOT-T отправляет вам

POST, тело application/x-www-form-urlencoded.
В PHP — $_POST.

Пример заявки. Полезные ответы — в answer (готовый текст) и в items (по каждому вопросу).

{
  "id": 9001,
  "feedback_id": 15,
  "bot_id": 1,
  "answer": "Логин:\nuser01\n\nТариф:\n30 дней",
  "created_time": "2024-05-21 12:10",
  "notice_time": null,
  "deleted_time": "",
  "data": "{\"order_id\":1001}",
  "status": {
    "id": 1,
    "title": "Не прочитан"
  },
  "user": {
    "id": 100500,
    "telegram_id": 182352323552,
    "username": "buyer",
    "first_name": "Иван",
    "last_name": "Иванов"
  },
  "items": [
    {
      "id": 31,
      "answer_id": 9001,
      "type": 1,
      "input": {
        "id": 501,
        "answer": "user01"
      },
      "file": null,
      "select": null,
      "crossroad": null,
      "main_input": {
        "id": 31,
        "text": "Логин",
        "type": 1,
        "feedback_id": 15,
        "confirm": false
      }
    },
    {
      "id": 32,
      "answer_id": 9001,
      "type": 3,
      "input": null,
      "file": null,
      "select": {
        "id": 88,
        "options": [
          {
            "id": 12,
            "option": {
              "id": 12,
              "text": "30 дней"
            }
          }
        ]
      },
      "crossroad": null,
      "main_input": {
        "id": 32,
        "text": "Тариф",
        "type": 3,
        "feedback_id": 15,
        "confirm": false
      }
    }
  ]
}
ПолеЗачем
idID заявки
dataСтрока JSON. Для формы товара: {"order_id":1001}
answerВсе ответы одним текстом
items[].type1 текст, 2 файл, 3 выбор, 4 развилка
items[].input.answerОтвет на текстовый вопрос
items[].select.options[].option.textВыбранный вариант
items[].main_input.textТекст вопроса
user.telegram_idКому отвечать

data приходит строкой. Перед использованием разберите JSON:

$meta = json_decode((string)($_POST['data'] ?? ''), true);
$orderId = (int)($meta['order_id'] ?? 0);
$login = $_POST['items'][0]['input']['answer'] ?? '';

Что вы должны ответить

HTTP 200, заголовок Content-Type: application/json, поле result.

Выдать текст покупателю:

{
  "result": true,
  "data": {
    "message": "Ваш ключ: <b>KEY-ABC-123</b>",
    "is_repeat": false
  }
}
ПолеОписание
resulttrue — заявка обработана
data.messageHTML-текст. BOT-T отправит его покупателю в Telegram. Если поля нет — сообщение не уйдёт
data.is_repeattrue — удалить заявку и заново показать форму. По умолчанию не повторять

Ошибка (заявка помечается прочитанной, текст уходит в лог, покупателю не отправляется):

{
  "result": false,
  "message": "Тариф недоступен"
}

data.message не заменяет update-product. Чтобы ключ сохранился в заказе:

$meta = json_decode((string)($_POST['data'] ?? ''), true);
$orderId = (int)($meta['order_id'] ?? 0);
$key = 'KEY-ABC-123';

if ($orderId > 0) {
    botShopOrder('update-product', [
        'order_id' => $orderId,
        'product' => $key,
    ]);
}

header('Content-Type: application/json');
echo json_encode([
    'result' => true,
    'data' => [
        'message' => 'Ваш ключ: <b>' . htmlspecialchars($key) . '</b>',
        'is_repeat' => false,
    ],
], JSON_UNESCAPED_UNICODE);

Повторный send-product здесь не нужен: текст уже уходит через data.message.


Когда что использовать

ЗадачаКак
Узнать об оплатеВебхук сценария 1
Записать ключ в заказupdate-product
Отправить сохранённый ключ ещё разsend-product
Собрать данные и сразу ответить в чатСценарий 2, data.message
Произвольное сообщение из конструктораsend-message или send-request

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

СимптомЧто проверить
Вебхук оплаты не приходитURL модуля API у категории, заказ оплачен
Заявка обратной связи не приходитИнтеграция CUSTOM, в «Публичный ключ» — ваш HTTPS URL, форма заполнена до конца
Нельзя изменить содержимое неоплаченного...update-product до оплаты или для отменённого заказа
Покупатель ничего не получилНет send-product или пустой product. В сценарии 2 нет data.message
Нет telegram_id для заказаЗаказ без Telegram
Повторная выдача другого ключаИдемпотентность по id заказа
Ответ CUSTOM не принятНет JSON, нет result, HTTP не 200

Чек-лист

Сценарий 1:

  • У категории указан HTTPS URL уведомления после оплаты
  • Endpoint читает $_POST, отвечает 2xx
  • Повтор вебхука не создаёт новый ключ
  • Вызываются update-product, затем send-product

Сценарий 2:

  • Форма привязана к товару
  • В интеграции CUSTOM указан ваш URL
  • Ответ — JSON с result и data.message
  • Если ключ должен храниться в заказе — ещё и update-product по data.order_id