$ sudo teach IT
Модуль 4 · Checks — крипто-чеки

Урок 4.3 — Изображения и QR для чеков

Научимся генерировать QR-коды и изображения чеков, получать ссылки для шеринга и интегрировать визуальное представление чеков в свои приложения.

Крипто-чеки — это не только цифровые активы, но и их визуальное представление. aiosend позволяет получить QR-код для любого чека, сгенерировать изображение-превью (с конвертацией в фиат) и создать ссылки для отправки в мессенджеры. В этом уроке мы разберём все способы визуализации чеков.

📱

check.qr — QR-код чека

Свойство check.qr возвращает URL-ссылку на QR-код чека. Это синхронное свойство (не async), потому что оно просто формирует URL на основе bot_check_url. Никакого HTTP-запроса не происходит.

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

cp = CryptoPay(token="YOUR_TOKEN")

# Создаём чек
check = await cp.create_check(amount=50, asset="USDT")

# Получаем QR-код (синхронно, не await!)
qr_url = check.qr
print(f"QR-код: {qr_url}")
# → https://qr.crypt.bot/?url=https://pay.crypt.bot/check/...

# Используем в HTML или Telegram
html = f'QR Code'

# Отправляем в Telegram
# await bot.send_photo(chat_id, photo=qr_url)

🔍 Как формируется QR-URL?

Свойство check.qr использует метод network.get_qr(), который формирует URL вида: https://qr.crypt.bot/?url={bot_check_url}. Это официальный QR-генератор от Crypto Pay. Если тебе нужен кастомный QR-код (другого размера, цвета), ты можешь взять check.bot_check_url и передать его в любой сторонний генератор QR.

Свойство qr доступно у любого объекта Check — как только что созданного, так и полученного через get_check() или get_checks().

Python · QR для существующего чека
# Получаем существующий чек и его QR
check = await cp.get_check(check_id=42)

# QR-код для активного чека (можно активировать)
if check.status == "active":
    print(f"QR для активации: {check.qr}")

# QR-код для уже активированного чека (просто информация)
if check.status == "activated":
    print(f"QR (история): {check.qr}")

# Свойство работает для любого статуса
print(f"Ссылка на чек: {check.bot_check_url}")
print(f"QR URL: {check.qr}")
🖼️

check.get_image() — изображение чека с конвертацией

Метод check.get_image(fiat) возвращает URL на изображение-превью чека. Изображение показывает сумму в криптовалюте и (опционально) эквивалент в фиатной валюте. Это идеально для встраивания в веб-страницы, Telegram-сообщения или email-рассылки.

Python · Сигнатура метода
async def get_image(self, fiat: str | None = None) -> str

# Параметры:
#   fiat: str | None — фиатная валюта для отображения
#         эквивалентной суммы (USD, EUR, RUB и т.д.)
#         Если None — показывается только крипто-сумма.
#
# Возвращает: str — URL на сгенерированное изображение
Python · Примеры get_image()
from aiosend import CryptoPay

cp = CryptoPay(token="YOUR_TOKEN")

check = await cp.create_check(amount=100, asset="USDT")

# Без фиата — только крипто-сумма
image_url = await check.get_image()
print(f"Изображение: {image_url}")
# → https://imggen.send.tg/check/...?lang=en

# С фиатом — покажет эквивалент в USD
image_url_usd = await check.get_image(fiat="USD")
print(f"С USD: {image_url_usd}")

# С EUR
image_url_eur = await check.get_image(fiat="EUR")
print(f"С EUR: {image_url_eur}")

# С RUB
image_url_rub = await check.get_image(fiat="RUB")
print(f"С RUB: {image_url_rub}")

💡 Как работает генерация изображения?

Метод get_image() обращается к сервису imggen.send.tg, который генерирует PNG-изображение чека. Если указан параметр fiat, сервис конвертирует сумму по текущему курсу и показывает оба значения. Изображение кешируется — повторные запросы с теми же параметрами возвращают тот же URL.

Метод является асинхронным, потому что он делает HTTP-запрос к сервису генерации изображений. Результат — строка с URL.

Python · Отправка изображения чека в Telegram
from aiosend import CryptoPay

async def send_check_to_user(cp: CryptoPay, check_id: int, chat_id: int):
    """Отправляет изображение чека пользователю в Telegram."""
    check = await cp.get_check(check_id=check_id)

    # Получаем изображение с конвертацией в USD
    image_url = await check.get_image(fiat="USD")

    # Здесь используй Telegram Bot API для отправки
    # await bot.send_photo(
    #     chat_id=chat_id,
    #     photo=image_url,
    #     caption=f"🎁 Чек на {check.amount} {check.asset}\n"
    #             f"Статус: {check.status}\n"
    #             f"Ссылка: {check.bot_check_url}",
    # )

    print(f"Изображение чека: {image_url}")
    print(f"Ссылка для активации: {check.bot_check_url}")
    print(f"QR: {check.qr}")
    return image_url
🔗

bot_check_url — ссылка на чек в CryptoBot

Поле bot_check_url — это прямая ссылка на чек в @CryptoBot. По этой ссылке пользователь может активировать чек (получить средства). Ссылка имеет формат: https://pay.crypt.bot/check/UNIQUE_ID.

Эта ссылка используется в паре с QR-кодом и изображением. Ты можешь:

  • Отправить её текстом в Telegram
  • Закодировать в QR-код (через check.qr)
  • Встроить в HTML-страницу как ссылку
  • Использовать в кнопках Telegram-бота
Python · Использование bot_check_url
from aiosend import CryptoPay

cp = CryptoPay(token="YOUR_TOKEN")
check = await cp.create_check(amount=25, asset="USDT")

# Прямая ссылка для активации
url = check.bot_check_url
print(f"Отправьте пользователю: {url}")

# Ссылка в HTML
html_link = f'Активировать чек на {check.amount} {check.asset}'

# Ссылка в Telegram-разметке
tg_link = f'[{check.amount} {check.asset}]({url})'

# Кнопка в Telegram-боте (aiogram)
# from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
# keyboard = InlineKeyboardMarkup(inline_keyboard=[
#     [InlineKeyboardButton(text=f"🎁 Получить {check.amount} {check.asset}", url=url)]
# ])
🌐

Методы Network: get_check_image() и get_qr()

Класс Network (доступный через cp.session.network) предоставляет низкоуровневые методы для генерации изображений и QR-кодов. Метод check.get_image() внутри вызывает network.get_check_image(), а check.qr — network.get_qr().

Network.get_check_image()

  • Принимает check_id и fiat
  • Возвращает URL изображения
  • Асинхронный метод

Network.get_qr()

  • Принимает link (URL)
  • Возвращает URL QR-кода
  • Синхронный метод
Python · Использование Network напрямую
from aiosend import CryptoPay

cp = CryptoPay(token="YOUR_TOKEN")
network = cp.session.network

# Используем network.get_qr() для произвольной ссылки
check = await cp.get_check(check_id=42)
qr_url = network.get_qr(check.bot_check_url)
print(f"QR: {qr_url}")

# Это эквивалентно check.qr:
print(f"check.qr: {check.qr}")  # то же самое

# Используем network.get_check_image() напрямую
image_url = await network.get_check_image(
    check_id=check.check_id,
    fiat="USD",
)
print(f"Изображение: {image_url}")

# Эквивалентно check.get_image(fiat="USD"):
print(f"check.get_image: {await check.get_image(fiat='USD')}")

💡 Когда использовать Network напрямую?

Используй Network.get_qr(), когда тебе нужно получить QR-код для произвольной ссылки, а не только для чека. Например, для инвойсов (invoice.bot_invoice_url). Метод Network.get_check_image() полезен, когда у тебя нет объекта Check, а есть только check_id.

Python · QR для инвойса через Network
from aiosend import CryptoPay

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

# QR для инвойса — используем Network.get_qr()
qr_url = cp.session.network.get_qr(invoice.bot_invoice_url)

# QR для чека — используем check.qr
check = await cp.create_check(amount=10, asset="USDT")
qr_url_check = check.qr  # то же самое: network.get_qr(check.bot_check_url)

print(f"QR инвойса: {qr_url}")
print(f"QR чека: {qr_url_check}")
📤

Генерация URL для шеринга чека

Комбинируя bot_check_url, QR-код и изображение, ты можешь создать полноценный блок для отправки чека пользователю. Вот несколько сценариев шеринга:

Python · Функция для генерации всех URL чека
from aiosend import CryptoPay

class CheckShareKit:
    """Генерирует все URL для шеринга чека."""

    def __init__(self, cp: CryptoPay):
        self.cp = cp
        self.network = cp.session.network

    async def generate(self, check_id: int, fiat: str = "USD") -> dict:
        """Генерирует все URL для чека."""
        check = await self.cp.get_check(check_id=check_id)

        return {
            "check_id": check.check_id,
            "amount": check.amount,
            "asset": check.asset,
            "status": check.status,
            "bot_url": check.bot_check_url,
            "qr_url": check.qr,
            "image_url": await check.get_image(fiat=fiat),
            "image_no_fiat": await check.get_image(),
            "share_text": (
                f"🎁 Я дарю тебе {check.amount} {check.asset}!\n"
                f"Активируй чек: {check.bot_check_url}"
            ),
        }

    async def share_to_telegram(self, check_id: int, chat_id: int):
        """Отправляет чек в Telegram (пример)."""
        kit = await self.generate(check_id)

        # Отправляем изображение с подписью
        # await bot.send_photo(
        #     chat_id=chat_id,
        #     photo=kit["image_url"],
        #     caption=kit["share_text"],
        # )

        # Или отправляем как кнопку
        # from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
        # keyboard = InlineKeyboardMarkup(inline_keyboard=[
        #     [InlineKeyboardButton(
        #         text=f"🎁 Получить {kit['amount']} {kit['asset']}",
        #         url=kit["bot_url"],
        #     )]
        # ])
        # await bot.send_message(
        #     chat_id=chat_id,
        #     text=f"Вам подарок! 🎉",
        #     reply_markup=keyboard,
        # )

        print(f"Шеринг готов:")
        print(f"  Ссылка: {kit['bot_url']}")
        print(f"  QR: {kit['qr_url']}")
        print(f"  Изображение: {kit['image_url']}")


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

    # Проверяем — генерируем URL для чека #42
    urls = await kit.generate(check_id=42, fiat="USD")
    print(f"Ссылка для активации: {urls['bot_url']}")
    print(f"QR: {urls['qr_url']}")
    print(f"Изображение: {urls['image_url']}")

    # Отправляем пользователю
    # await kit.share_to_telegram(check_id=42, chat_id=123456789)


if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

🔍 Структура URL изображения

URL изображения формируется сервисом imggen.send.tg и выглядит так: https://imggen.send.tg/check/CHECK_ID?lang=en&fiat=USD. Параметр fiat опционален. Если его нет — на изображении будет только крипто-сумма. Если есть — добавится эквивалент в фиате.

🎨

Пример: визуальный просмотрщик чеков

Давай напишем функцию, которая выводит все активные чеки в виде ссылок с изображениями и QR. Это может быть основа для панели управления или отчёта.

Python · Просмотрщик чеков с изображениями
from aiosend import CryptoPay, CheckStatus

async def visualize_checks(cp: CryptoPay, fiat: str = "USD"):
    """Выводит все активные чеки с изображениями и QR."""
    checks = await cp.get_checks(status=CheckStatus.ACTIVE)

    if not checks:
        print("Нет активных чеков.")
        return

    print(f"📋 Найдено активных чеков: {len(checks)}")
    print()

    for i, check in enumerate(checks, 1):
        image_url = await check.get_image(fiat=fiat) if fiat else await check.get_image()

        print(f"{'='*60}")
        print(f"  Чек #{i}")
        print(f"  ID: {check.check_id}")
        print(f"  Сумма: {check.amount} {check.asset}")
        print(f"  Статус: {check.status}")
        print(f"  Создан: {check.created_at}")
        print(f"  Ссылка: {check.bot_check_url}")
        print(f"  QR: {check.qr}")
        print(f"  Изображение: {image_url}")
        if check.payload:
            print(f"  Payload: {check.payload}")
        print()

    # Выводим таблицу в HTML-формате
    html_rows = []
    for check in checks:
        img = await check.get_image(fiat=fiat)
        html_rows.append(f"""
        
            {check.check_id}
            {check.amount} {check.asset}
            {check.status}
            
            
            Активировать
        
        """)

    html = f"""
    {''.join(html_rows)}
    
IDСуммаСтатусQRИзображениеСсылка
""" with open("checks_report.html", "w") as f: f.write(html) print("✅ HTML-отчёт сохранён: checks_report.html") async def main(): cp = CryptoPay(token="YOUR_TOKEN") await visualize_checks(cp, fiat="USD") if __name__ == "__main__": import asyncio asyncio.run(main())

💡 Практическое применение

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

🖼️

Массовая генерация изображений и бот-check-url

Если тебе нужно сгенерировать изображения для всех чеков определённого типа — например, для рассылки или отчёта — используй комбинацию get_checks() и get_image().

Python · Массовая генерация изображений чеков
from aiosend import CryptoPay, CheckStatus

async def batch_check_images(
    cp: CryptoPay,
    asset: str = "USDT",
    fiat: str = "USD",
) -> list[dict]:
    """Генерирует изображения для всех чеков в указанном активе."""
    checks = await cp.get_checks(asset=asset, status=CheckStatus.ACTIVE)
    results = []

    for check in checks:
        image_url = await check.get_image(fiat=fiat)
        results.append({
            "check_id": check.check_id,
            "amount": check.amount,
            "asset": check.asset,
            "bot_url": check.bot_check_url,
            "qr_url": check.qr,
            "image_url": image_url,
        })
        print(f"✅ Чек #{check.check_id}: {check.amount} {check.asset}")
        print(f"   Ссылка: {check.bot_check_url}")
        print(f"   Изображение: {image_url}")
        print()

    return results

async def main():
    cp = CryptoPay(token="YOUR_TOKEN")
    images = await batch_check_images(cp, asset="USDT", fiat="USD")
    print(f"Сгенерировано изображений: {len(images)}")


if __name__ == "__main__":
    import asyncio
    asyncio.run(main())
⚠️

Граничные случаи и ограничения

Неверный фиат в get_image()

Если передать неподдерживаемую фиатную валюту в check.get_image(fiat), сервис imggen.send.tg может вернуть ошибку или изображение без конвертации. Используй только поддерживаемые фиаты: USD, EUR, RUB, BYN, UAH, GBP, CNY, KZT, UZS, GEL, TRY, AED.

QR-код для активированного чека

Свойство check.qr работает для любого чека — как активного, так и активированного. Однако QR-код активированного чека ведёт на страницу, где чек уже использован. Пользователь не сможет его активировать повторно. Учитывай это при отправке QR — убедись, что чек ещё активен.

Кеширование изображений

Сервис imggen.send.tg кеширует сгенерированные изображения. Если ты вызываешь get_image() с теми же параметрами повторно, URL может быть одинаковым. Это нормально — изображение обновится, если изменится курс валюты (для изображений с fiat).

Доступность сервиса imggen

Генерация изображений зависит от внешнего сервиса imggen.send.tg. Если сервис временно недоступен, get_image() может выбросить исключение или вернуть битый URL. Всегда обрабатывай эту ситуацию и имей запасной вариант — например, отправку простой текстовой ссылки вместо изображения.

📌

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

1️⃣
check.qr — синхронное свойство, возвращает URL QR-кода. Не требует await. Формируется на основе bot_check_url.
2️⃣
check.get_image(fiat) — асинхронный метод, возвращает URL изображения чека с опциональным фиатным эквивалентом.
3️⃣
bot_check_url — поле объекта Check, прямая ссылка на активацию в @CryptoBot.
4️⃣
Network.get_qr(link) — синхронный метод для получения QR произвольной ссылки (например, для инвойса).
5️⃣
Network.get_check_image() — низкоуровневый асинхронный метод для генерации изображения по check_id.
6️⃣
QR всегда доступен — свойство qr работает для чеков любого статуса. Но для активированных чеков QR бесполезен.
7️⃣
Изображение = async — get_image() делает HTTP-запрос к imggen.send.tg. Используй await. При ошибках сервиса предусмотри fallback.
🎯

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

Задание: Создай генератор визитки чека

Напиши функцию generate_check_card(), которая создаёт «визитку» чека — набор всех визуальных элементов для отправки пользователю. Функция должна:

  • Принимать check_id и опционально fiat
  • Возвращать словарь с: bot_check_url, qr_url, image_url (с fiat), image_url (без fiat)
  • Генерировать готовый текст для Telegram-сообщения со всеми ссылками
  • Генерировать HTML-код для встраивания на веб-страницу
  • Проверять статус чека: если активирован — добавлять предупреждение
  • Обрабатывать возможные ошибки (чек не найден, сервис недоступен)

Подсказка:

Python · Шаблон решения
import asyncio
from aiosend import CryptoPay
from aiosend.exceptions import APIError

async def generate_check_card(
    cp: CryptoPay,
    check_id: int,
    fiat: str | None = "USD",
) -> dict | None:
    try:
        check = await cp.get_check(check_id=check_id)

        card = {
            "check_id": check.check_id,
            "amount": check.amount,
            "asset": check.asset,
            "status": check.status,
            "bot_check_url": check.bot_check_url,
            "qr_url": check.qr,
            "image_url_with_fiat": await check.get_image(fiat=fiat) if fiat else None,
            "image_url_no_fiat": await check.get_image(),
            "is_activated": check.status == "activated",
        }

        # Предупреждение для активированного чека
        if card["is_activated"]:
            card["warning"] = "⚠️ Этот чек уже активирован!"
        else:
            card["warning"] = None

        # Telegram-сообщение
        card["telegram_message"] = (
            f"🎁 Крипто-чек!\n"
            f"Сумма: {card['amount']} {card['asset']}\n"
            f"Статус: {card['status']}\n"
            f"Ссылка: {card['bot_check_url']}\n"
            f"QR: {card['qr_url']}"
        )

        # HTML-код
        card["html_code"] = (
            f'
' f'

Чек на {card["amount"]} {card["asset"]}

' f'

Статус: {card["status"]}

' f'QR' f'
Активировать' f'
' ) return card except APIError as e: print(f"Ошибка API: {e}") except Exception as e: print(f"Неизвестная ошибка: {e}") return None async def main(): cp = CryptoPay(token="YOUR_TOKEN") card = await generate_check_card(cp, check_id=42, fiat="USD") if card: print(card["telegram_message"]) if __name__ == "__main__": asyncio.run(main())
🌍

Интеграция в веб-приложения

Изображения и QR-коды чеков отлично интегрируются в веб-приложения. Вот несколько примеров использования в различных фреймворках.

FastAPI — эндпоинт для получения данных чека

Python · FastAPI endpoint для чека
from fastapi import FastAPI, HTTPException
from aiosend import CryptoPay

app = FastAPI()
cp = CryptoPay(token="YOUR_TOKEN")

@app.get("/api/check/{check_id}")
async def get_check_info(check_id: int, fiat: str = "USD"):
    """Возвращает JSON с данными чека и ссылками."""
    try:
        check = await cp.get_check(check_id=check_id)
        image_url = await check.get_image(fiat=fiat)

        return {
            "check_id": check.check_id,
            "amount": check.amount,
            "asset": check.asset,
            "status": check.status,
            "bot_url": check.bot_check_url,
            "qr_url": check.qr,
            "image_url": image_url,
            "created_at": check.created_at,
        }
    except Exception as e:
        raise HTTPException(status_code=404, detail=str(e))


@app.get("/api/check/{check_id}/qr")
async def get_check_qr(check_id: int):
    """Перенаправляет на QR-код чека."""
    check = await cp.get_check(check_id=check_id)
    from fastapi.responses import RedirectResponse
    return RedirectResponse(url=check.qr)

HTML-шаблон для отображения чека

HTML · Шаблон карточки чека
{% if check %}

🎁 Крипто-чек

Check preview
QR
{{ check.amount }} {{ check.asset }}
Статус: {{ check.status }}
Получить {{ check.amount }} {{ check.asset }}
{% endif %}

Telegram Bot — отправка чека в сообщении

Python · Отправка чека через aiogram
from aiogram import Bot, Dispatcher, types
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from aiosend import CryptoPay

bot = Bot(token="TELEGRAM_BOT_TOKEN")
dp = Dispatcher()
cp = CryptoPay(token="CRYPTOPAY_TOKEN")

async def send_check(chat_id: int, check_id: int):
    """Отправляет чек пользователю в Telegram."""
    check = await cp.get_check(check_id=check_id)
    image_url = await check.get_image(fiat="USD")

    keyboard = InlineKeyboardMarkup(inline_keyboard=[
        [InlineKeyboardButton(
            text=f"🎁 Получить {check.amount} {check.asset}",
            url=check.bot_check_url,
        )],
    ])

    await bot.send_photo(
        chat_id=chat_id,
        photo=image_url,
        caption=(
            f"🎉 Вам подарок!\n"
            f"Сумма: {check.amount} {check.asset}\n"
            f"[QR]({check.qr})"
        ),
        parse_mode="Markdown",
        reply_markup=keyboard,
    )

# Пример хендлера:
# @dp.message(Command("bonus"))
# async def bonus_handler(message: types.Message):
#     check = await cp.create_check(amount=10, asset="USDT")
#     await send_check(message.chat.id, check.check_id)

💡 Все 3 способа визуализации

Для одного чека ты можешь использовать: 1) QR-код (check.qr) — быстрый доступ через камеру; 2) Изображение (check.get_image) — для встраивания в сообщения и web; 3) Текстовую ссылку (check.bot_check_url) — для отправки текстом. Комбинируй эти три способа для максимального удобства пользователей.

🔄

Полный lifecycle: от создания до активации

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

Python · Полный lifecycle чека
import asyncio
from aiosend import CryptoPay, CheckStatus

async def check_lifecycle_demo(cp: CryptoPay):
    """Демонстрирует полный lifecycle чека с визуализацией."""

    # Шаг 1: Создаём чек
    print("Шаг 1: Создание чека")
    check = await cp.create_check(amount=15, asset="USDT")
    print(f"   Чек #{check.check_id} создан")

    # Шаг 2: Получаем визуальные элементы
    print("\nШаг 2: Визуальные элементы")
    print(f"   bot_check_url: {check.bot_check_url}")
    print(f"   QR: {check.qr}")
    image_usd = await check.get_image(fiat="USD")
    print(f"   Image (USD): {image_usd}")
    image_raw = await check.get_image()
    print(f"   Image (raw): {image_raw}")

    # Шаг 3: Отправляем пользователю (симуляция)
    print("\nШаг 3: Отправка пользователю")
    print(f"   Отправляем изображение: {image_usd}")
    print(f"   И кнопку со ссылкой: {check.bot_check_url}")

    # Шаг 4: Ожидаем активации (polling)
    print("\nШаг 4: Ожидание активации...")
    while True:
        check = await cp.get_check(check_id=check.check_id)
        if check.status == CheckStatus.ACTIVATED:
            print(f"   ✅ Чек активирован!")
            print(f"   Кем: user #{check.activated_by}")
            print(f"   Когда: {check.activated_at}")
            break
        await asyncio.sleep(2)

    # Шаг 5: Пост-обработка
    print("\nШаг 5: Пост-обработка")
    print(f"   Финальный статус: {check.status}")
    print(f"   Чек активирован, QR больше не актуален")
    print(f"   QR (история): {check.qr}")

    return check


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


if __name__ == "__main__":
    asyncio.run(main())

💡 Важный нюанс: QR после активации

Помни, что QR-код (check.qr) остаётся доступным даже после активации чека. Но он ведёт на страницу, где чек уже использован. Если ты отправляешь QR пользователю — убедись, что чек ещё активен (check.status == "active"). Используй статус для проверки перед отправкой.

Урок 4.3: Изображения и QR для чеков

10 вопросов