$ sudo teach IT
Модуль 3 · Invoices — управление счетами

Урок 3.4 — Ссылки, QR-коды и кнопки оплаты

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

После создания инвойса возникает вопрос: как отправить его покупателю? Crypto Pay предоставляет три типа ссылок, QR-код и богатые возможности по настройке интерфейса оплаты. В этом уроке мы научимся выбирать правильный тип ссылки для разных сценариев, настраивать кнопки после оплаты, управлять комментариями и анонимностью, а также использовать скрытые сообщения для пост-пеймент контента.

🔗

Три типа ссылок на инвойс

У каждого инвойса есть три URL-свойства: bot_invoice_url, mini_app_invoice_url и web_app_invoice_url. Все три ведут к оплате одного и того же счёта, но открываются в разных средах. Выбор зависит от того, где находится твой пользователь.

Свойство Формат ссылки Открывается в Лучший сценарий
bot_invoice_url t.me/CryptoBot/...
t.me/CryptoTestnetBot/...
Telegram @CryptoBot Пользователи уже в Telegram, боты
mini_app_invoice_url t.me/CryptoBot/...?app=... Telegram Mini App Встроенный WebView в Telegram
web_app_invoice_url pay.crypt.bot/invoice/... Браузер (Web) Веб-сайты, email-рассылки

bot_invoice_url — классическая ссылка в бота

Самый распространённый тип. Открывает диалог с @CryptoBot (или @CryptoTestnetBot) и показывает покупателю интерфейс оплаты. Идеально подходит для Telegram-ботов: ты отправляешь эту ссылку пользователю, он нажимает — и сразу видит счёт.

mini_app_invoice_url — ссылка Mini App

Открывает интерфейс оплаты как Telegram Mini App (WebView). Это более современный и быстрый способ: пользователь не покидает твой бот или приложение, оплата происходит во встроенном окне. Используй этот тип, если твой бот уже использует Mini Apps.

web_app_invoice_url — веб-ссылка

Обычная HTTPS-ссылка на сайт pay.crypt.bot. Открывается в любом браузере. Подходит для веб-сайтов, email-писем, рассылок и любых сценариев вне Telegram. Покупатель может оплатить счёт даже без установленного Telegram — через Web-версию.

Python · Все три типа ссылок
import asyncio
from aiosend import CryptoPay

async def main():
    cp = CryptoPay(token="YOUR_TOKEN")
    invoice = await cp.create_invoice(amount=10, asset="USDT")

    print("Три способа отправить счёт покупателю:\n")

    print(f"1️⃣ Бот: {invoice.bot_invoice_url}")
    print(f"   → 'Оплатить через @CryptoBot'")
    print(f"    Используй: в Telegram-ботах, кнопки Inline-Keyboard\n")

    print(f"2️⃣ Mini App: {invoice.mini_app_invoice_url}")
    print(f"   → 'Оплатить в Mini App'")
    print(f"    Используй: в WebView, встроенные платежи\n")

    print(f"3️⃣ Web: {invoice.web_app_invoice_url}")
    print(f"   → 'Оплатить на сайте pay.crypt.bot'")
    print(f"    Используй: на веб-сайтах, в email-письмах")

asyncio.run(main())

Как выбрать тип ссылки?

В Telegram-ботах: используй bot_invoice_url — он открывается быстрее всего. На веб-сайтах: web_app_invoice_url — работает в любом браузере. В Mini App-интерфейсах: mini_app_invoice_url — не покидает контекст приложения.

📱

QR-коды для инвойсов

Объект Invoice имеет свойство qr, которое возвращает прямую ссылку на изображение QR-кода. Это готовый к использованию URL картинки, которую можно отправить пользователю или встроить в веб-страницу.

Python · Получение QR-кода инвойса
import asyncio
from aiosend import CryptoPay

async def main():
    cp = CryptoPay(token="YOUR_TOKEN")
    invoice = await cp.create_invoice(amount=10, asset="USDT")

    # Свойство qr — готовая ссылка на изображение QR-кода
    qr_url = invoice.qr
    print(f"QR-код для оплаты: {qr_url}")
    # → https://qr.crypt.bot/?url=https://pay.crypt.bot/invoice/...

    # Также можно получить QR через Network
    qr_via_network = cp.session.network.get_qr(invoice.bot_invoice_url)
    print(f"QR через Network: {qr_via_network}")
    # Результат тот же

asyncio.run(main())

Как работает QR-код внутри? Свойство invoice.qr использует метод Network.get_qr(), который формирует URL вида https://qr.crypt.bot/?url={bot_invoice_url}. Это официальный QR-генератор Crypto Pay.

💡 Интеграция QR-кода в веб-страницу

Просто вставь ссылку в <img src="...">: <img src="https://qr.crypt.bot/?url=..." alt="QR для оплаты">. Или используй библиотеку qrcode для генерации QR на своей стороне, если нужен кастомный дизайн.

QR-код для физических точек оплаты

QR-коды особенно полезны в офлайн-сценариях: напечатай QR на чеке, экране терминала или наклейке — покупатель сканирует и оплачивает.

Python · Генерация QR для печати
import asyncio
from aiosend import CryptoPay

async def generate_printable_qr(cp: CryptoPay, amount: float, asset: str):
    """Создаёт инвойс и возвращает QR-ссылку для печати."""
    invoice = await cp.create_invoice(
        amount=amount,
        asset=asset,
        description="Оплата на кассе",
        expires_in=3600,  # 1 час на оплату
    )

    result = {
        "id": invoice.invoice_id,
        "amount": invoice.amount,
        "asset": invoice.asset,
        "qr_url": invoice.qr,
        "bot_url": invoice.bot_invoice_url,
        "web_url": invoice.web_app_invoice_url,
        "expires_at": invoice.expires_at,
    }

    print(f"QR для печати: {result['qr_url']}")
    print(f"Сумма: {result['amount']} {result['asset']}")
    print(f"Истекает: {result['expires_at']}")

    return result

async def main():
    cp = CryptoPay(token="YOUR_TOKEN")
    # Для физической точки: сумма фиксированная, срок 1 час
    await generate_printable_qr(cp, 25, "USDT")

asyncio.run(main())
🔘

paid_btn_name и paid_btn_url — кнопка после оплаты

После успешной оплаты в @CryptoBot покупатель видит кнопку. С помощью параметров paid_btn_name и paid_btn_url ты можешь настроить её вид и действие.

Доступные значения paid_btn_name (через enum PaidBtnName):

Значение Enum Текст кнопки Куда ведёт
"viewItem" VIEWITEM «View Item» / «Посмотреть товар» Страница товара на твоём сайте
"openChannel" OPENCHANNEL «Open Channel» / «Открыть канал» Telegram-канал или чат
"openBot" OPENBOT «Open Bot» / «Открыть бота» Твоего Telegram-бота
"callback" CALLBACK «Send» / «Отправить» Твой сервер (callback URL)

‼️ Важно: paid_btn_url обязателен

Если указан paid_btn_name, то paid_btn_url обязателен. Без URL кнопка не появится. И наоборот: если paid_btn_name не указан — кнопки после оплаты не будет, даже если указан paid_btn_url.

Пример 1: Кнопка VIEWITEM

Покупатель оплатил и видит кнопку «Посмотреть товар», ведущую на страницу скачивания.

Python · VIEWITEM
from aiosend import CryptoPay, PaidBtnName

async def viewitem_example():
    cp = CryptoPay(token="YOUR_TOKEN")

    invoice = await cp.create_invoice(
        amount=29.99,
        asset="USDT",
        description="Премиум-шаблон Notion",
        paid_btn_name=PaidBtnName.VIEWITEM,
        paid_btn_url="https://example.com/download/premium-template",
        hidden_message="Ссылка для скачивания: https://example.com/dl/abc123",
    )
    print(f"Счёт: {invoice.amount} {invoice.asset}")
    print(f"Кнопка: VIEWITEM → {invoice.paid_btn_url}")
    return invoice

Пример 2: Кнопка OPENCHANNEL

После оплаты доступа к закрытому Telegram-каналу показываем кнопку «Открыть канал».

Python · OPENCHANNEL
from aiosend import CryptoPay, PaidBtnName

async def openchannel_example():
    cp = CryptoPay(token="YOUR_TOKEN")

    invoice = await cp.create_invoice(
        amount=50,
        fiat="USD",
        description="Доступ к закрытому каналу News+",
        paid_btn_name=PaidBtnName.OPENCHANNEL,
        paid_btn_url="https://t.me/private_news_channel",
        payload="channel_access_user_123",
    )
    print(f"Счёт: {invoice.amount} {invoice.fiat}")
    print(f"Кнопка: OPENCHANNEL → {invoice.paid_btn_url}")
    return invoice

Пример 3: Кнопка OPENBOT

После оплаты возвращаем пользователя обратно в твоего бота с параметром start.

Python · OPENBOT
from aiosend import CryptoPay, PaidBtnName

async def openbot_example():
    cp = CryptoPay(token="YOUR_TOKEN")

    invoice = await cp.create_invoice(
        amount=15,
        asset="TON",
        description="Билет на вебинар",
        paid_btn_name=PaidBtnName.OPENBOT,
        paid_btn_url="https://t.me/your_bot?start=webinar_2024",
        allow_anonymous=False,
        payload="webinar_ticket_user_456",
    )
    print(f"Счёт: {invoice.amount} {invoice.asset}")
    print(f"Кнопка: OPENBOT → {invoice.paid_btn_url}")
    return invoice

Пример 4: Кнопка CALLBACK

После оплаты отправляем POST-запрос на твой сервер для кастомной обработки.

Python · CALLBACK
from aiosend import CryptoPay, PaidBtnName

async def callback_example():
    cp = CryptoPay(token="YOUR_TOKEN")

    invoice = await cp.create_invoice(
        amount=99,
        asset="USDT",
        description="Годовая подписка",
        paid_btn_name=PaidBtnName.CALLBACK,
        paid_btn_url="https://api.example.com/payment/callback",
        payload='{"user_id":789,"plan":"annual"}',
    )
    print(f"Счёт: {invoice.amount} {invoice.asset}")
    print(f"Кнопка: CALLBACK → {invoice.paid_btn_url}")
    # При нажатии на кнопку Crypto Pay отправит POST с данными инвойса
    # на указанный URL. Твой сервер должен обработать этот запрос.
    return invoice
💬

allow_comments и allow_anonymous

Два логических параметра управляют поведением платёжного интерфейса. Они влияют на то, что видит и может делать покупатель во время оплаты.

allow_comments

По умолчанию True.

  • True — покупатель может оставить комментарий при оплате
  • False — поле комментария скрыто
  • Комментарий виден в данных оплаченного инвойса (поле comment)

allow_anonymous

По умолчанию True.

  • True — оплата без авторизации в @CryptoBot
  • False — требуется авторизация, ты получишь user_id
  • Полезно для возвратов и идентификации плательщика
Python · Настройка комментариев и анонимности
import asyncio
from aiosend import CryptoPay

async def main():
    cp = CryptoPay(token="YOUR_TOKEN")

    # Счёт с обязательной авторизацией и комментариями
    invoice1 = await cp.create_invoice(
        amount=10,
        asset="USDT",
        allow_comments=True,
        allow_anonymous=False,
        description="Оплата с идентификацией",
    )
    print(f"Счёт #{invoice1.invoice_id}: анонимность=OFF, комментарии=ON")

    # Быстрая оплата без лишних полей
    invoice2 = await cp.create_invoice(
        amount=5,
        asset="TON",
        allow_comments=False,
        allow_anonymous=True,
        description="Быстрая оплата",
    )
    print(f"Счёт #{invoice2.invoice_id}: анонимность=ON, комментарии=OFF")

asyncio.run(main())

⚠️ Когда отключать allow_anonymous?

Отключай анонимность, если тебе нужно точно знать, кто оплатил — например, для выдачи доступа к каналу, активации подписки или возврата средств. В этом случае в объекте Invoice будет заполнено поле user_id покупателя (приходит через webhook или после invoice.update()).

🤫

hidden_message — скрытое сообщение после оплаты

hidden_message — это текст, который покупатель видит только после успешной оплаты. До оплаты сообщение скрыто. Это идеальный механизм для доставки цифровых товаров: ссылок на скачивание, промокодов, инструкций, кодов активации.

Характеристика description hidden_message payload
Когда видно До оплаты После оплаты Никогда
Максимум символов 1024 2048 4096
Видит покупатель Да Да Нет
Назначение Описание товара Цифровая доставка Внутренняя логика
Python · Использование hidden_message
import asyncio
import secrets
from aiosend import CryptoPay, PaidBtnName

async def main():
    cp = CryptoPay(token="YOUR_TOKEN")

    # Генерируем уникальный код активации
    activation_code = secrets.token_hex(8).upper()

    invoice = await cp.create_invoice(
        amount=19.99,
        asset="USDT",
        description="Активация Premium на 1 месяц",

        # Покупатель увидит это сообщение ПОСЛЕ оплаты
        hidden_message=(
            "✅ Оплата прошла успешно!\n\n"
            f"Ваш код активации:\n{activation_code}\n\n"
            "Как активировать:\n"
            "1. Откройте бота: @your_bot\n"
            "2. Отправьте команду /activate\n"
            "3. Введите код выше\n\n"
            "Ссылка: https://t.me/your_bot"
        ),

        # Кнопка после оплаты
        paid_btn_name=PaidBtnName.OPENBOT,
        paid_btn_url="https://t.me/your_bot?start=activated",

        # Внутренние данные
        payload=activation_code,
    )

    print(f"Счёт #{invoice.invoice_id}")
    print(f"Код активации (в payload): {activation_code}")
    print(f"Ссылка: {invoice.bot_invoice_url}")

asyncio.run(main())

⚠️ hidden_message не для секретов

Хотя hidden_message скрыт до оплаты, он передаётся через API Crypto Pay и хранится в истории. Не используй его для паролей, приватных ключей или конфиденциальных данных. Для真正的 секретов используй payload как ссылку на твою БД, где хранится настоящий секрет.

🧩

Полный пример: магазин с пост-оплатой

Соберём всё вместе: ссылки всех типов, QR-код, кастомная кнопка после оплаты, скрытое сообщение, управление комментариями и анонимностью.

Python · Магазин цифровых товаров
import asyncio
import json
import secrets
from aiosend import CryptoPay, PaidBtnName

class DigitalGoodsStore:
    """Магазин цифровых товаров с оплатой через Crypto Pay."""

    def __init__(self, token: str):
        self.cp = CryptoPay(token=token)

    async def sell_product(
        self,
        product_name: str,
        price: float,
        asset: str,
        download_link: str,
    ) -> dict:
        """
        Продаёт цифровой товар.
        Возвращает словарь со всеми ссылками и QR.
        """
        # Генерируем уникальный код заказа
        order_id = secrets.token_hex(6)

        invoice = await self.cp.create_invoice(
            amount=price,
            asset=asset,
            description=f"Купить: {product_name}",
            hidden_message=(
                f"🎉 Спасибо за покупку!\n\n"
                f"Товар: {product_name}\n"
                f"Заказ: #{order_id}\n\n"
                f"Ссылка для скачивания:\n{download_link}\n\n"
                f"Срок действия ссылки: 48 часов"
            ),
            paid_btn_name=PaidBtnName.VIEWITEM,
            paid_btn_url=download_link,
            payload=json.dumps({
                "order_id": order_id,
                "product": product_name,
                "price": price,
            }),
            allow_comments=False,
            allow_anonymous=False,  # требуется регистрация
        )

        return {
            "order_id": order_id,
            "invoice_id": invoice.invoice_id,
            "amount": invoice.amount,
            "asset": invoice.asset,
            "status": invoice.status,

            # Все три типа ссылок
            "bot_url": invoice.bot_invoice_url,
            "mini_app_url": invoice.mini_app_invoice_url,
            "web_url": invoice.web_app_invoice_url,

            # QR-код
            "qr_url": invoice.qr,

            # Кнопка после оплаты
            "paid_btn": invoice.paid_btn_name,
            "paid_btn_url": invoice.paid_btn_url,
        }

    async def present_invoice(self, invoice_data: dict):
        """Выводит красивое представление всех ссылок."""
        print(f"\n{'='*50}")
        print(f"   Заказ #{invoice_data['order_id']}")
        print(f"   Сумма: {invoice_data['amount']} {invoice_data['asset']}")
        print(f"{'='*50}")
        print(f"🔗 Ссылка в боте:       {invoice_data['bot_url']}")
        print(f"🔗 Ссылка Mini App:     {invoice_data['mini_app_url']}")
        print(f"🔗 Ссылка Web:         {invoice_data['web_url']}")
        print(f"📱 QR-код:              {invoice_data['qr_url']}")
        print(f"🔘 Кнопка:              {invoice_data['paid_btn']}")
        print(f"📎 URL кнопки:          {invoice_data['paid_btn_url']}")
        print(f"{'='*50}\n")

async def main():
    store = DigitalGoodsStore("YOUR_TOKEN")

    # Продаём первый товар
    result1 = await store.sell_product(
        product_name="Notion Template Pro",
        price=29.99,
        asset="USDT",
        download_link="https://example.com/dl/template-pro",
    )
    await store.present_invoice(result1)

    # Продаём второй товар
    result2 = await store.sell_product(
        product_name="Видеокурс Python Advanced",
        price=49.00,
        asset="USDT",
        download_link="https://example.com/dl/python-advanced",
    )
    await store.present_invoice(result2)

asyncio.run(main())
🎯

Какой тип ссылки выбрать?

Сценарий Рекомендуемая ссылка Почему
Telegram-бот, кнопка «Оплатить» bot_invoice_url Открывается внутри Telegram мгновенно
Mini App / WebView mini_app_invoice_url Не покидает контекст приложения
Веб-сайт, лендинг web_app_invoice_url Работает в браузере, без Telegram
Email-рассылка web_app_invoice_url Открывается с любого устройства
QR-код на кассе invoice.qr Готовое изображение для печати
Соцсети (Instagram, TikTok) web_app_invoice_url Не требует установки Telegram
Ссылка в описании видео web_app_invoice_url Универсальная, работает везде

💡 Простое правило

Если пользователь в Telegram — используй bot_invoice_url. Если не в Telegram (или ты не уверен) — используй web_app_invoice_url. Для Mini Apps — mini_app_invoice_url. Для печати — invoice.qr.

⚠️

Граничные случаи

Некорректный paid_btn_name

Если передать строку, не соответствующую одному из четырёх допустимых значений (viewItem, openChannel, openBot, callback), API вернёт ошибку MethodValuesError. Всегда используй enum PaidBtnName для избежания опечаток.

paid_btn_url без paid_btn_name

Если указать paid_btn_url без paid_btn_name, URL будет проигнорирован. Кнопка не появится. Ошибки не будет — API просто не использует URL, если кнопка не задана. Поэтому всегда проверяй, что оба параметра передаются вместе.

QR-код для просроченного инвойса

QR-код остаётся доступным даже после истечения срока инвойса. Однако при сканировании покупатель увидит сообщение об ошибке. Рекомендуется генерировать QR-коды с небольшим сроком жизни и менять их после оплаты или истечения.

hidden_message и теги

hidden_message поддерживает только обычный текст. HTML-теги, Markdown или другие форматы не обрабатываются. Если нужно форматирование — используй простые переносы строк (\n) и эмодзи.

Ссылки для TESTNET

Если ты используешь TESTNET, все три типа ссылок будут вести на тестовые боты и сайты: t.me/CryptoTestnetBot/... и testnet-pay.crypt.bot/.... Покупатель не сможет оплатить тестовый счёт в MAINNET и наоборот.

📌

Что важно запомнить

1️⃣
Три типа ссылок: bot_invoice_url (Telegram), mini_app_invoice_url (Mini App), web_app_invoice_url (Web). Выбирай по контексту пользователя.
2️⃣
QR-код — свойство invoice.qr. Готовая ссылка на изображение. Также доступен через Network.get_qr().
3️⃣
paid_btn_name — четыре варианта: VIEWITEM, OPENCHANNEL, OPENBOT, CALLBACK. paid_btn_url обязателен при указании name.
4️⃣
allow_anonymous=False — включает идентификацию плательщика. allow_comments=False — убирает поле комментария.
5️⃣
hidden_message — до 2048 символов, виден только после оплаты. Идеален для цифровой доставки.
6️⃣
Ссылки на TESTNET и MAINNET разные. В TESTNET все ссылки ведут на testnet-pay.crypt.bot и CryptoTestnetBot.
🎯

Практическое задание

Задание: Платёжный модуль для интернет-магазина

Создай класс PaymentModule, который:

  • Создаёт инвойс с полным набором параметров: сумма, валюта, описание, скрытое сообщение
  • Принимает тип желаемой ссылки (bot/mini_app/web) и возвращает соответствующую
  • Генерирует QR-код и возвращает его вместе со ссылкой
  • Настраивает кнопку после оплаты в зависимости от типа товара:
    • Для цифровых товаров — VIEWITEM + ссылка на скачивание
    • Для доступа к каналу — OPENCHANNEL + ссылка на канал
    • Для подписки — OPENBOT + ссылка на бота
  • Управляет allow_comments и allow_anonymous
  • Выводит JSON со всеми данными для отправки клиенту

Подсказка:

Python · Шаблон решения
import asyncio
from enum import Enum
from aiosend import CryptoPay, PaidBtnName

class ProductType(Enum):
    DIGITAL = "digital"
    CHANNEL = "channel"
    SUBSCRIPTION = "subscription"

class PaymentModule:
    """Платёжный модуль интернет-магазина."""

    def __init__(self, token: str):
        self.cp = CryptoPay(token=token)

    def _get_button_config(self, product_type: ProductType, url: str):
        """Возвращает настройки кнопки в зависимости от типа товара."""
        configs = {
            ProductType.DIGITAL: (PaidBtnName.VIEWITEM, url),
            ProductType.CHANNEL: (PaidBtnName.OPENCHANNEL, url),
            ProductType.SUBSCRIPTION: (PaidBtnName.OPENBOT, url),
        }
        return configs[product_type]

    async def create_payment(
        self,
        amount: float,
        asset: str,
        description: str,
        hidden_message: str,
        product_type: ProductType,
        button_url: str,
        link_type: str = "bot",
        require_auth: bool = False,
    ) -> dict:
        """Создаёт платёж и возвращает все данные для клиента."""
        btn_name, btn_url = self._get_button_config(product_type, button_url)

        invoice = await self.cp.create_invoice(
            amount=amount,
            asset=asset,
            description=description,
            hidden_message=hidden_message,
            paid_btn_name=btn_name,
            paid_btn_url=btn_url,
            allow_anonymous=not require_auth,
            allow_comments=False,
        )

        # Выбираем нужный тип ссылки
        link_map = {
            "bot": invoice.bot_invoice_url,
            "mini_app": invoice.mini_app_invoice_url,
            "web": invoice.web_app_invoice_url,
        }
        payment_url = link_map.get(link_type, invoice.bot_invoice_url)

        return {
            "success": True,
            "invoice_id": invoice.invoice_id,
            "amount": invoice.amount,
            "asset": invoice.asset,
            "status": invoice.status,
            "payment_url": payment_url,
            "qr_url": invoice.qr,
            "button_name": invoice.paid_btn_name,
            "button_url": invoice.paid_btn_url,
        }

# Пример использования
async def main():
    pm = PaymentModule("YOUR_TOKEN")

    # Продажа цифрового товара
    result = await pm.create_payment(
        amount=19.99,
        asset="USDT",
        description="PDF-руководство по Python",
        hidden_message="Ссылка: https://example.com/dl/python-book",
        product_type=ProductType.DIGITAL,
        button_url="https://example.com/dl/python-book",
        link_type="bot",
    )
    print(result)

asyncio.run(main())
🌐

Особенности ссылок для TESTNET

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

Тип ссылки MAINNET TESTNET
bot_invoice_url t.me/CryptoBot/... t.me/CryptoTestnetBot/...
mini_app_invoice_url t.me/CryptoBot/...?app=... t.me/CryptoTestnetBot/...?app=...
web_app_invoice_url pay.crypt.bot/invoice/... testnet-pay.crypt.bot/invoice/...
invoice.qr qr.crypt.bot/?url=... qr.crypt.bot/?url=... (тот же)

⚠️ Не отправляй TESTNET-ссылку реальному пользователю

Ссылка на @CryptoTestnetBot не сможет быть оплачена реальным пользователем — ему нужно авторизоваться в тестовом боте, что не имеет смысла. Всегда проверяй, из какой сети (MAINNET/TESTNET) был создан инвойс, прежде чем отправлять ссылку.

Python · Определение сети по ссылке
import asyncio
from aiosend import CryptoPay, TESTNET

def detect_network_from_url(url: str) -> str:
    """Определяет сеть по ссылке на инвойс."""
    if "testnet" in url.lower():
        return "TESTNET"
    return "MAINNET"

async def main():
    # Создаём инвойс в TESTNET
    cp = CryptoPay(token="YOUR_TEST_TOKEN", network=TESTNET)
    invoice = await cp.create_invoice(amount=5, asset="USDT")

    print(f"bot URL: {invoice.bot_invoice_url}")
    print(f"Сеть: {detect_network_from_url(invoice.bot_invoice_url)}")
    # → TESTNET

    # Проверяем, что ссылка ведёт в правильного бота
    if "@CryptoTestnetBot" in invoice.bot_invoice_url:
        print("✅ Это тестовая ссылка")
    elif "@CryptoBot" in invoice.bot_invoice_url:
        print("✅ Это основная ссылка")

asyncio.run(main())
📋

Шпаргалка: все URL-свойства Invoice

Для быстрого доступа — все URL-свойства объекта Invoice в одной таблице:

Свойство Тип Описание
bot_invoice_url str Ссылка в @CryptoBot (или @CryptoTestnetBot). Основной способ оплаты для Telegram.
mini_app_invoice_url str Ссылка в Mini App Telegram. Для встроенного WebView.
web_app_invoice_url str Веб-ссылка на pay.crypt.bot. Для браузера, email, соцсетей.
qr str Ссылка на изображение QR-кода (ведёт на bot_invoice_url).
paid_btn_name str | None Название кнопки после оплаты (viewItem, openChannel, openBot, callback).
paid_btn_url str | None URL кнопки после оплаты.
hidden_message str | None Сообщение после оплаты (до 2048 символов).
payload str | None Внутренние данные (до 4096 символов), невидимые покупателю.

💡 Быстрый доступ к ссылкам

Все URL-свойства доступны сразу после создания инвойса — не нужно делать дополнительных запросов к API. Просто создал — и сразу можешь отправлять любую ссылку или QR-код.

Урок 3.4: Ссылки, QR-коды и кнопки оплаты

5 вопросов