Платёжная ссылка — самый короткий способ начать продавать из бота. Вам не нужны Mini App, витрина и корзина: достаточно сообщения «Счёт на 3 200 ₽ за консультацию» с кнопкой, которая ведёт на форму оплаты. Первый рабочий вариант делается за час, потому что со стороны бота это один HTTP-запрос и одна inline-кнопка.
Тонкость в другом: ссылка живёт ограниченное время, часть людей по ней не платит, и на эти два факта нужен сценарий. О нём — большая часть текста.
Минимальный старт без витрины
Фрилансер-дизайнер держал бота на четыре команды: показать портфолио, узнать цену, написать в личку, оплатить. Оплата была реквизитами в текстовом сообщении, и каждый второй перевод приходил без комментария — потом полчаса разбираться, кто это и за что. Замена на ссылку убрала разбор целиком: назначение и сумма зашиты в платёж, а колбэк приносит order_id.
Что нужно, чтобы повторить:
- Команда бота.
/payили кнопка «Оплатить» после диалога о цене. - Запись в базе. Строка с
tg_user_id, услугой, суммой и своимorder_id. - Запрос на создание платежа.
POST /api/v1/payments, заголовкиX-API-KeyиX-Nonce. - Ответ. Из него берёте
pay_url,payment_idиexpires_at. - Сообщение. Inline-кнопка с текстом «Оплатить 3 200 ₽» и адресом
pay_url.
Сумму передавайте строкой: "amount": "3200.00". Дробные числа в JSON — источник копеечных расхождений при сверке.
Ссылка рождается из заказа, а не из строки в коде
Соблазн собрать адрес шаблоном — «а вдруг там просто сумма в параметре» — возникает почти у всех. Так делать нельзя по двум причинам. Первая: адрес с суммой в открытом виде правится в браузере, и человек оплатит 10 ₽ вместо 10 000 ₽. Вторая: у вас не останется своей записи о заказе, и деньги придут ниоткуда.
Правильный порядок — сначала строка в orders со статусом pending, потом платёж на её основе, потом ссылка из ответа. Тогда order_id связывает три мира: ваш бот, платёжный сервис и бухгалтерию. Он же обеспечивает идемпотентность: повторный запрос с тем же order_id не создаст второй платёж, если покупатель дважды ткнул в кнопку. Подробнее этот механизм разобран в статье об идемпотентности платёжных запросов.
Сколько живёт ссылка
Ответ приходит в поле expires_at вместе с самой ссылкой. Сохраняйте его в базу рядом с заказом — без этого бот не сможет отличить «ещё можно платить» от «уже поздно».
| Что продаёте | Разумный срок жизни | Почему |
|---|---|---|
| Цифровой товар с моментальной выдачей | 15–30 минут | Решение принимается сразу, длинный срок только копит мусор |
| Услуга по договорённости, счёт от менеджера | 1–3 дня | Человеку нужно свериться с календарём или бюджетом |
| Бронь места, тура, слота | Столько, сколько держите бронь | Срок ссылки и срок брони обязаны совпадать |
Когда время вышло, сервис присылает событие payment.expired. Обработайте его: переведите заказ в expired, освободите бронь и отредактируйте сообщение с кнопкой, чтобы человек не тыкал в мёртвый адрес. Сценарий с бронью подробно расписан в материале про оплату бронирования в Telegram-боте.
Человек не оплатил: что делать дальше
Считайте, что 40–60 % открывших ссылку не доведут дело до конца с первого раза. Это нормальная воронка, а не поломка. Разберите её на понятные состояния и ведите каждое отдельно.
- Ссылку не открывали. Скорее всего, сообщение утонуло в непрочитанных. Помогает короткое напоминание через несколько часов.
- Открыл, но не выбрал банк. Часто человек не был готов платить прямо сейчас. Предложите вторую попытку и уточните, остаётся ли заказ в силе.
- Дошёл до банка и вернулся. Возможен отказ банка или нехватка средств. Тут уместно предложить другой способ оплаты — например, картой вместо СБП.
- Пришло
payment.canceled. Заказ закрывайте и не напоминайте больше: человек отказался осознанно.
Диагностика по кодам ошибок и типичным отказам собрана в статье что делать, если платёж не прошёл.
Напоминания, которые не бесят
Напоминание в личных сообщениях — тонкий инструмент: перегнёте, и человек нажмёт «Заблокировать бота», после чего вы потеряете и заказ, и канал связи. Рабочая схема — два касания и стоп.
- Через 2–3 часа. Одно предложение и свежая кнопка: «Заказ на курс ещё держится, ссылка действует до 21:00».
- За час до истечения. Прямо скажите, что будет дальше: место освободится, цена вернётся к обычной, доступ не откроется.
- Больше не пишите. Третье сообщение приносит отписки, а не деньги.
Каждое напоминание должно нести новую ссылку, если старая уже просрочена. Отправлять текст «оплатите, пожалуйста» с мёртвой кнопкой — верный способ получить сообщение в поддержку вместо оплаты. И обязательно проверяйте статус заказа перед отправкой: школа английского однажды разослала полсотни напоминаний людям, которые заплатили десять минут назад, потому что джоба брала список по дате создания, а не по актуальному статусу.
Чем подтверждается оплата
Скриншот из банка, слова «я всё отправил» и даже возврат человека в чат — это не подтверждение. Заказ переводит в paid только колбэк с событием payment.paid, у которого проверена подпись X-Signature: HMAC-SHA256 от X-Timestamp, точки и сырого тела запроса, ключ — signing_secret вашей кассы. Считайте её до разбора JSON и сравнивайте constant-time.
Отдельно про success_redirect_url: он нужен, чтобы человеку было куда вернуться после банка, и только для этого. Страница «Спасибо, оплата прошла» может открыться и у того, кто просто подставил адрес в браузере.
Когда одной ссылки уже мало
Ссылка отлично закрывает разовые продажи и счета от менеджера. Она начинает мешать, когда:
- у вас каталог на несколько десятков позиций — покупателю нужна витрина, а не переписка;
- вы продаёте доступ на период и его нужно продлевать — тогда смотрите в сторону оплаты подписки в Telegram-боте;
- оплату принимают несколько менеджеров и нужны разные кассы и разграничение доступа.
Готовый сценарий выставления счетов ссылкой описан в решении платёжные ссылки. Статус продавца, чек и возвраты при этом остаются вашей зоной ответственности: самозанятый формирует чек в «Мой налог» и держит в голове лимит 2,4 млн ₽ в год, а платёжный сервис отвечает за техническую часть. Категорию проекта и доступные способы оплаты подтверждает модерация.