Qut Pay Сайт Кабинет База знаний Инструкции Документация API ҚАЗРУС
ГлавнаяБаза знаний → Для вашего бизнеса

Продажи через Telegram-бота

Обновлено: 2026-09-14 · Версия в Markdown

Коротко

Telegram-бот не обращается в Qut Pay напрямую — между ними стоит ваш сервер. Покупатель выбирает товар в боте → бот сообщает вашему серверу → сервер создаёт счёт → бот присылает картинку QR или ссылку на оплату (либо покупателю прилетает пуш в Kaspi) → после подтверждения к вам приходит вебхук → сервер говорит боту выдать товар. API-ключ живёт только на сервере, в коде бота его нет.

Как это работает

ШагКтоЧто делает
1ПокупательВыбирает товар в боте и нажимает «Оплатить»
2БотШлёт запрос на ваш сервер (chat_id, товар, сумма)
3СерверPOST /api/v1/invoices, кладёт chat_id в metadata
4БотОтправляет картинку qrImageUrl или ссылку payUrl
5ПокупательПодтверждает оплату в Kaspi
6Qut PayШлёт на сервер invoice.paid
7СерверПо metadata.chat_id сообщает боту, бот выдаёт товар

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

Какой метод API используется

Создание счёта — POST /api/v1/invoices. Два вида:

Если номер покупателя известен, в боте удобнее phone: ничего сканировать не нужно, Kaspi открывается сам. Номер можно получить кнопкой «Отправить контакт» прямо в Telegram.

Остальное: GET /api/v1/invoices/{id} — статус, POST /api/v1/invoices/{id}/cancel — отмена, POST /api/v1/invoices/{id}/refund — возврат.

Короткий пример

Python:

import requests

r = requests.post(
    "https://api.qut.kz/api/v1/invoices",
    headers={"X-API-Key": API_KEY, "Idempotency-Key": f"tg-{chat_id}-{cart_id}"},
    json={
        "amount": 5900,
        "kind": "qr",
        "description": "Курс: первый модуль",
        "externalOrderId": str(cart_id),
        "metadata": {"chat_id": chat_id, "bot": "kurs_bot"},
    },
    timeout=15,
)
inv = r.json()
bot.send_photo(chat_id, inv["qrImageUrl"], caption=f"Оплатить: {inv['payUrl']}")

Node.js:

const res = await fetch('https://api.qut.kz/api/v1/invoices', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.QUTPAY_KEY,
    'Idempotency-Key': `tg-${chatId}-${cartId}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    amount: 5900,
    kind: 'phone',
    description: 'Курс: первый модуль',
    customer: { phone: '77010000000' },
    metadata: { chat_id: chatId, bot: 'kurs_bot' },
  }),
});
const inv = await res.json();

На стороне вебхука берёте сырое тело, считаете HMAC-SHA256(secret, timestamp + "." + rawBody), сравниваете с заголовком и по payload.metadata.chat_id сообщаете боту. Есть готовые SDK: Node.js, PHP, Python.

Как не накопить неоплаченные счета

В боте это реальная проблема: люди жмут «Оплатить» и уходят. Несколько сотен открытых счетов могут упереться в суточную защиту.

Несколько брендов в одном боте

Если в боте продаётся несколько магазинов или направлений, есть два пути.

Одна организация, разная пометка. Все деньги приходят на один счёт в Kaspi. Бренд пишете в metadata ({"brand": "shop_a"}) и по нему разделяете отчётность. Самый простой вариант.

Разные ключи. Для каждого направления заводите отдельный API-ключ — тогда счета удобно фильтровать по источнику. Ключ можно привязать к конкретному кассиру: привязанный ключ видит только счета этого кассира, на чужие отвечает 404. Про кассиров: Можно ли подключить несколько кассиров.

Если деньги должны идти на разные счета — это уже разные организации, у каждой свой кассир и свой тариф: Несколько организаций в одном аккаунте.

На что обратить внимание

Вопросы и ответы

Можно положить API-ключ в код бота? Нет. Даже если бот и ключ на одном сервере, читайте ключ из переменной окружения и не коммитьте в репозиторий. Если ключ утёк — удалите его и создайте новый.

А если я не знаю номер покупателя? Делайте QR-счёт, для него номер не нужен. Пуш на телефон работает только при kind: "phone".

Если бот упал, деньги потеряются? Нет. Оплата проходит в Kaspi, деньги приходят на ваш счёт. Когда бот поднимется, вебхук придёт снова — мы повторяем доставку 11 раз, пока не получим 2xx.

Можно продавать в групповом чате? Бота можно добавить в группу, но ссылку на оплату лучше слать в личный чат: в ней видны сумма и описание.

Покупатель может отсканировать QR прямо из бота? На одном телефоне это неудобно. Поэтому в боте лучше давать ссылку payUrl или пуш kind: "phone", а картинку QR оставить запасным вариантом.

Связанные статьи

Приём Kaspi для интернет-магазинаПолная схема от корзины до статуса «оплачен»: счёт, страница оплаты, вебхук. Способы без кода для Tilda, WooCommerce и OpenCart, и путь через API для самописного сайта.Продажи через InstagramПорядок работы в директе: ссылка на оплату, ручной счёт из кабинета, счёт командой из Telegram-бота. Всё работает без кода. Как вести учёт и не перепутать заказы.Продажи в прямом эфире TikTokКак выставлять счёт за секунды прямо во время эфира: пуш по номеру телефона, команда /invoice в Telegram-боте, QR на экране, работа с помощником и контроль оплат.Вебхук не приходит — как найти причинуСчёт оплачен, а на ваш сервер уведомление не пришло. С чего начать диагностику, какая причина встречается чаще всего и как проверить её одним запросом.Можно ли подключить несколько кассировДа, можно. У каждого кассира свой номер и своя привязка. Что такое основной кассир, как привязать API-ключ к конкретному кассиру и почему лимит остаётся общим.

Остались вопросы? WhatsApp +77788813333 · kazprose@gmail.com
Написать можно и из кабинета: Поддержка.

Qut Pay — независимый сервис, не аффилирован с АО «Kaspi Bank». Kaspi и Kaspi Pay — товарные знаки их правообладателя.