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

Урок 3.1 — Создание инвойсов

Научимся создавать счета (инвойсы) для приёма платежей. Разберём все параметры метода create_invoice(), типы данных, валюты и практические примеры.

Инвойс (счёт) — это запрос на оплату, который создаётся в системе Crypto Pay и отправляется покупателю. Покупатель видит сумму, валюту и оплачивает через @CryptoBot. После оплаты ты получаешь уведомление. В этом уроке мы рассмотрим, как создавать инвойсы с любыми настройками.

🧾

Что такое инвойс в aiosend

Invoice (счёт) — это ключевой объект в Crypto Pay API. Через него ты просишь пользователя оплатить определённую сумму в определённой валюте. Crypto Pay создаёт платёжную ссылку, кнопку или QR-код, по которым покупатель переходит в @CryptoBot и совершает оплату.

Инвойс проходит через три статуса:

🟡
ACTIVE
Ожидает оплаты
🟢
PAID
Оплачен
🔴
EXPIRED
Истёк срок

Статусы меняются автоматически: при создании инвойс получает статус ACTIVE. Когда покупатель оплачивает — статус меняется на PAID. Если оплата не поступила в течение заданного времени — статус становится EXPIRED.

Общая схема работы с инвойсами:

1. Создаёшь инвойс через await cp.create_invoice(...)

2. Получаешь объект Invoice со ссылками и QR

3. Отправляешь ссылку или QR покупателю

4. Ожидаешь оплату (через polling, webhook или вручную)

5. После оплаты обрабатываешь результат

📋

Метод create_invoice() — полный разбор

Метод create_invoice() — основной инструмент для создания счетов. Доступен как у экземпляра CryptoPay, так и у Network. Разберём каждый параметр подробно.

Python · Сигнатура метода
async def create_invoice(
    self,
    amount: float | str,
    asset: str | None = None,
    fiat: str | None = None,
    accepted_assets: list[str] | None = None,
    currency_type: str | None = None,
    swap_to: str | None = None,
    description: str | None = None,
    hidden_message: str | None = None,
    paid_btn_name: str | None = None,
    paid_btn_url: str | None = None,
    payload: str | None = None,
    allow_comments: bool = True,
    allow_anonymous: bool = True,
    expires_in: int | None = None,
) -> Invoice

Все параметры, кроме amount, являются опциональными. Однако asset или fiat должны быть указаны (иначе API вернёт ошибку).

Python · Таблица параметров create_invoice()
Параметр Тип Обязательный Описание
amount float | str ✅ Да Сумма счёта. Для криптовалют можно передавать строку с большим количеством знаков после запятой (например "0.000001").
asset str | None Нет* Криптовалюта счёта (например "USDT", "TON"). Должен быть указан либо asset, либо fiat.
fiat str | None Нет* Фиатная валюта счёта (например "USD", "EUR"). Должен быть указан либо asset, либо fiat.
accepted_assets list[str] | None Нет Список криптовалют, которыми можно оплатить счёт (только для fiat-инвойсов). Покупатель сможет выбрать любую из списка.
currency_type str | None Нет Тип валюты: "crypto" или "fiat". Определяет, какой тип валюты используется для суммы.
swap_to str | None Нет Автоматическая конвертация (своп) в указанный актив после оплаты. Например, принять USDT и сразу конвертировать в TON.
description str | None Нет Описание счёта (до 1024 символов). Отображается в Crypto Pay при оплате.
hidden_message str | None Нет Скрытое сообщение, которое увидит покупатель ПОСЛЕ оплаты (до 2048 символов).
paid_btn_name str | None Нет Название кнопки после оплаты. Одно из: "viewItem", "openChannel", "openBot", "callback".
paid_btn_url str | None Нет URL для кнопки после оплаты. Обязателен, если указан paid_btn_name.
payload str | None Нет Произвольные данные (до 4096 символов). Не отображаются покупателю, используются для внутренней логики.
allow_comments bool Нет Разрешить комментарии при оплате (по умолчанию True).
allow_anonymous bool Нет Разрешить анонимную оплату (по умолчанию True).
expires_in int | None Нет Время жизни счёта в секундах. Минимум 1 секунда, максимум — 2678400 (31 день).

* — asset или fiat должны быть указаны. Если указан asset, счёт создаётся в криптовалюте. Если указан fiat — в фиатной валюте, и покупатель оплачивает эквивалент в криптовалюте по текущему курсу.

💰

Валюта счёта: asset, fiat, currency_type

При создании инвойса нужно указать, в какой валюте принимается платёж. У aiosend есть три взаимосвязанных параметра для настройки валюты: asset, fiat и currency_type.

Параметр asset

Указывает криптовалюту, в которой создаётся счёт. Допустимые значения:

USDT
TON
BTC
ETH
LTC
BNB
TRX
USDC
JET
SEND
SOL
XAUT

Параметр fiat

Указывает фиатную валюту для счёта. Сумма указывается в фиате, а покупатель оплачивает эквивалент в криптовалюте по текущему курсу Crypto Pay. Допустимые значения:

USD
EUR
RUB
BYN
UAH
GBP
CNY
KZT
UZS
GEL
TRY
AED

Параметр currency_type

Определяет, какой тип валюты используется. Два значения:

currency_type="crypto"

  • Сумма указывается в криптовалюте
  • Параметр asset обязателен
  • Покупатель платит ровно столько, сколько указано
  • Можно использовать accepted_assets для нескольких валют

currency_type="fiat"

  • Сумма указывается в фиатной валюте
  • Параметр fiat обязателен
  • Покупатель платит эквивалент в криптовалюте
  • Курс фиксируется в момент создания счёта

Важно! Если ты указываешь asset, то currency_type автоматически устанавливается в "crypto". Если указываешь fiat — в "fiat". Явно передавать currency_type нужно только в особых случаях (например, при создании fiat-счёта с accepted_assets).

Python · Примеры указания валюты
# Счёт в криптовалюте (USDT)
invoice = await cp.create_invoice(amount=100, asset="USDT")

# Счёт в фиате (USD)
invoice = await cp.create_invoice(amount=50, fiat="USD")

# Счёт в криптовалюте с явным currency_type
invoice = await cp.create_invoice(
    amount=0.5,
    asset="TON",
    currency_type="crypto",
)

# Счёт в фиате с явным currency_type
invoice = await cp.create_invoice(
    amount=100,
    fiat="EUR",
    currency_type="fiat",
)
🔄

accepted_assets — несколько валют для оплаты

Параметр accepted_assets позволяет указать список криптовалют, которыми покупатель может оплатить счёт. Это особенно полезно для fiat-инвойсов: ты указываешь сумму в долларах, а покупатель может оплатить USDT, TON, BTC или любой другой актив из списка.

Если accepted_assets не указан, то для fiat-счёта покупатель может оплатить любым активом, который поддерживает Crypto Pay. Если указан — только активами из списка.

Python · Пример с accepted_assets
# Счёт на 100 USD, оплатить можно только USDT или TON
invoice = await cp.create_invoice(
    amount=100,
    fiat="USD",
    accepted_assets=["USDT", "TON"],
)

# Счёт на 50 EUR, оплатить можно TON, BTC или ETH
invoice = await cp.create_invoice(
    amount=50,
    fiat="EUR",
    accepted_assets=["TON", "BTC", "ETH"],
)

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

Когда покупатель открывает счёт, Crypto Pay показывает сумму в фиате (например, 100 USD) и список доступных криптовалют для оплаты. Покупатель выбирает USDT, видит эквивалентную сумму в USDT (например, 100.5 USDT с учётом курса и комиссии) и подтверждает оплату.

🔄

swap_to — автоматическая конвертация

Параметр swap_to включает автоматическую конвертацию полученных средств в другой актив. Это мощная функция: ты можешь принять оплату в USDT, а на баланс получить TON (или любой другой поддерживаемый актив).

Варианты использования:

  • Принимать всё в USDT, но хранить в TON (меньше комиссий за вывод)
  • Принимать в любой криптовалюте, но конвертировать в стейблкоин
  • Автоматически обменивать полученные средства в SEND или JET для дальнейших операций
Python · Примеры с swap_to
# Принимаем USDT, на баланс получаем TON
invoice = await cp.create_invoice(
    amount=100,
    asset="USDT",
    swap_to="TON",
)

# Принимаем в фиате, конвертируем в USDC
invoice = await cp.create_invoice(
    amount=50,
    fiat="USD",
    swap_to="USDC",
)

# Принимаем BTC, конвертируем в USDT
invoice = await cp.create_invoice(
    amount=0.001,
    asset="BTC",
    swap_to="USDT",
)

Как это работает под капотом?

После того как покупатель оплачивает инвойс, Crypto Pay автоматически выполняет swap (обмен) полученной суммы в указанный актив по текущему рыночному курсу. На баланс твоего приложения зачисляется уже сконвертированная сумма. Комиссия за swap списывается дополнительно. Обрати внимание: swap возможен только между поддерживаемыми парами.

✉️

description и hidden_message — описание и секрет

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

description

  • Отображается ДО оплаты
  • Максимум 1024 символа
  • Виден всем при открытии счёта
  • Используется для названия товара/услуги

hidden_message

  • Отображается ПОСЛЕ оплаты
  • Максимум 2048 символов
  • Скрыт до момента оплаты
  • Используется для ссылок на товар, секретных кодов
Python · Пример с описанием и скрытым сообщением
invoice = await cp.create_invoice(
    amount=10,
    asset="USDT",
    description="Премиум-подписка на 1 месяц",
    hidden_message=(
        "Благодарим за покупку!\n"
        "Ваш промокод: PREMIUM-12345\n"
        "Активируйте по ссылке: https://example.com/activate"
    ),
)

⚠️ Важно про hidden_message

Не храни конфиденциальную информацию (пароли, ключи) в hidden_message. Сообщение передаётся через API Crypto Pay и хранится в истории. Используй его для промокодов, ссылок на скачивание, ID заказа — но не для секретов, которые нельзя показывать.

🔘

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

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

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

Значение Enum Что видит пользователь Когда использовать
"viewItem" PaidBtnName.VIEWITEM «View Item» / «Посмотреть товар» Цифровые товары, подписки
"openChannel" PaidBtnName.OPENCHANNEL «Open Channel» / «Открыть канал» Telegram-каналы, чаты
"openBot" PaidBtnName.OPENBOT «Open Bot» / «Открыть бота» Возврат в вашего бота
"callback" PaidBtnName.CALLBACK «Send» / «Отправить» (callback) Кастомная обработка через ваш сервер
Python · Примеры с кнопкой после оплаты
from aiosend import PaidBtnName

# Кнопка "Посмотреть товар"
invoice = await cp.create_invoice(
    amount=25,
    asset="USDT",
    paid_btn_name=PaidBtnName.VIEWITEM,
    paid_btn_url="https://example.com/download/item123",
)

# Кнопка "Открыть канал" — для продажи доступа к каналу
invoice = await cp.create_invoice(
    amount=50,
    fiat="USD",
    paid_btn_name=PaidBtnName.OPENCHANNEL,
    paid_btn_url="https://t.me/private_channel",
)

# Кнопка с callback — для кастомной обработки
invoice = await cp.create_invoice(
    amount=15,
    asset="TON",
    paid_btn_name=PaidBtnName.CALLBACK,
    paid_btn_url="https://api.example.com/payment/callback",
)

‼️ Важно

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

📦

payload — внутренние данные счёта

payload — это строка до 4096 символов, которая хранит произвольные данные, связанные со счётом. Покупатель не видит payload — это внутренний механизм для твоей логики.

Типичные сценарии использования:

  • ID товара: payload="product_123" — при обработке оплаты ты знаешь, какой товар купил пользователь
  • ID пользователя: payload="user_45678" — знаешь, кто оплатил
  • JSON-данные: payload='{"user_id":456,"item":"premium"}' — структурированные данные (можно использовать PayloadData)
  • ID заказа: payload="order_98765" — для связки с твоей CRM
Python · Пример с payload
import json

# Простой payload
invoice = await cp.create_invoice(
    amount=10,
    asset="USDT",
    payload="user_12345_product_premium",
)

# Структурированный JSON payload
payload_data = {
    "user_id": 12345,
    "product_id": "premium_month",
    "quantity": 1,
    "coupon": "SAVE10",
}
invoice = await cp.create_invoice(
    amount=20,
    fiat="USD",
    payload=json.dumps(payload_data),
)

PayloadData — типизированный payload

В aiosend есть специальный класс PayloadData для создания типизированных payload'ов. Мы подробно рассмотрим его в уроке 6.5. Он позволяет запаковать данные в структурированном виде и использовать MagicFilter для фильтрации событий.

💬

allow_comments и allow_anonymous — настройки оплаты

Эти два логических параметра управляют поведением платёжного интерфейса в @CryptoBot.

allow_comments=True

  • Покупатель может оставить комментарий при оплате
  • Значение по умолчанию: True
  • Комментарий виден в информации об инвойсе
  • Удобно, если нужна дополнительная информация от плательщика

allow_comments=False

  • Покупатель не может оставить комментарий
  • Упрощает процесс оплаты
  • Рекомендуется для быстрых платежей

allow_anonymous=True

  • Покупатель может оплатить анонимно (без привязки к аккаунту Crypto Pay)
  • Значение по умолчанию: True
  • Позволяет принимать платежи от любых пользователей

allow_anonymous=False

  • Покупатель должен быть авторизован в @CryptoBot
  • Ты сможешь узнать, кто именно платил (user_id)
  • Полезно для возвратов и идентификации плательщика
Python · Пример с комментариями и анонимностью
# Быстрая оплата без комментариев, но с идентификацией
invoice = await cp.create_invoice(
    amount=5,
    asset="USDT",
    allow_comments=False,
    allow_anonymous=False,
)

# Полная свобода: комментарии и анонимность разрешены
invoice = await cp.create_invoice(
    amount=100,
    fiat="RUB",
    allow_comments=True,
    allow_anonymous=True,
)

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

Если тебе нужно точно знать, кто оплатил (например, для выдачи товара на аккаунт), установи allow_anonymous=False. В этом случае при оплате покупатель авторизуется в @CryptoBot, и ты получишь его user_id в данных оплаченного инвойса.

⏱️

expires_in — время жизни счёта

Параметр expires_in задаёт время в секундах, через которое неоплаченный счёт автоматически перейдёт в статус EXPIRED.

expires_in Примерное время Когда использовать
60 1 минута Быстрые платежи, оплата «здесь и сейчас»
300 5 минут Стандартная оплата в боте
3600 1 час Долгая сессия оплаты, корзина товаров
86400 24 часа (1 день) Счета-фактуры, инвойсы на email
604800 7 дней Долгосрочные предложения
2678400 31 день Максимальный срок (лимит API)
Python · Пример с expires_in
# Счёт на 5 минут
invoice = await cp.create_invoice(
    amount=0.5,
    asset="TON",
    expires_in=300,
)

# Счёт на 24 часа
invoice = await cp.create_invoice(
    amount=100,
    fiat="USD",
    expires_in=86400,
)

# Без expires_in — используется стандартный срок Crypto Pay
# (обычно 2 часа, но может меняться)
invoice = await cp.create_invoice(
    amount=10,
    asset="USDT",
    # expires_in не указан → срок по умолчанию
)

Граничные значения expires_in

Минимальное значение: 1 секунда. Максимальное: 2 678 400 секунд (ровно 31 день). Если передать значение меньше 1 — API вернёт ошибку. Если больше 2678400 — также ошибка. Всегда проверяй, что expires_in находится в допустимом диапазоне.

📄

Тип Invoice — все поля объекта

Метод create_invoice() возвращает объект Invoice (Pydantic-модель). Вот все его поля:

Поле Тип Описание
invoice_id int Уникальный ID инвойса в системе Crypto Pay
amount str Сумма счёта (строка, чтобы сохранить точность)
asset str Криптовалюта счёта (например "USDT")
currency_type str Тип валюты: "crypto" или "fiat"
fiat str | None Фиатная валюта (если счёт в фиате)
accepted_assets list[str] | None Список разрешённых активов для оплаты
status str Статус: "active", "paid" или "expired"
description str | None Описание счёта
hidden_message str | None Скрытое сообщение (видно после оплаты)
payload str | None Внутренние данные счёта
paid_btn_name str | None Название кнопки после оплаты
paid_btn_url str | None URL кнопки после оплаты
comment str | None Комментарий покупателя (если allow_comments=True)
allow_comments bool Разрешены ли комментарии
allow_anonymous bool Разрешена ли анонимная оплата
created_at str Дата создания в формате ISO 8601
paid_at str | None Дата оплаты (если оплачен)
expires_at str | None Дата истечения срока
paid_usd_rate str | None Курс к USD на момент оплаты
usd_rate str | None Текущий курс к USD
paid_asset str | None Актив, которым оплатили (если отличается от asset)
paid_amount str | None Фактически оплаченная сумма
swap_to str | None Актив для автоматического свопа
swap_amount str | None Сумма после свопа
bot_invoice_url str Ссылка на счёт в боте (@CryptoBot)
mini_app_invoice_url str Ссылка на счёт в Mini App
web_app_invoice_url str Ссылка на счёт в Web App

Как видишь, объект Invoice содержит не только те данные, которые ты передал при создании, но и множество служебных полей: ссылки всех типов, курсы, даты и информацию об оплате.

Python · Доступ к полям инвойса
invoice = await cp.create_invoice(amount=100, asset="USDT")

print(f"ID: {invoice.invoice_id}")
print(f"Сумма: {invoice.amount} {invoice.asset}")
print(f"Статус: {invoice.status}")
print(f"Создан: {invoice.created_at}")
print(f"Ссылка в боте: {invoice.bot_invoice_url}")
print(f"Ссылка Mini App: {invoice.mini_app_invoice_url}")
print(f"Ссылка Web App: {invoice.web_app_invoice_url}")

# После оплаты будут доступны:
# print(f"Оплачено: {invoice.paid_amount} {invoice.paid_asset}")
# print(f"Курс: {invoice.paid_usd_rate}")
# print(f"Оплачено в: {invoice.paid_at}")
🧩

Практические примеры

Давай рассмотрим несколько реальных сценариев создания инвойсов от простых к сложным.

Пример 1: Простой крипто-счёт

Самый базовый случай: счёт на 50 USDT без дополнительных опций.

Python · Простой инвойс
import asyncio
from aiosend import CryptoPay

async def main():
    cp = CryptoPay(token="YOUR_TOKEN")
    invoice = await cp.create_invoice(amount=50, asset="USDT")
    print(f"Счёт #{invoice.invoice_id} создан!")
    print(f"Ссылка: {invoice.bot_invoice_url}")
    print(f"Статус: {invoice.status}")

asyncio.run(main())

Пример 2: Fiat-счёт с выбором валют

Счёт на 100 рублей с возможностью оплаты USDT или TON.

Python · Fiat-инвойс с accepted_assets
async def create_fiat_invoice():
    cp = CryptoPay(token="YOUR_TOKEN")
    invoice = await cp.create_invoice(
        amount=100,
        fiat="RUB",
        accepted_assets=["USDT", "TON"],
        description="Оплата заказа №123",
    )
    print(f"Счёт на {invoice.amount} {invoice.fiat}")
    print(f"Принимаем: {invoice.accepted_assets}")
    print(f"Ссылка: {invoice.bot_invoice_url}")
    return invoice

Пример 3: Счёт со swap

Принимаем USDT, на баланс получаем TON.

Python · Инвойс со swap
async def create_swap_invoice():
    cp = CryptoPay(token="YOUR_TOKEN")
    invoice = await cp.create_invoice(
        amount=50,
        asset="USDT",
        swap_to="TON",
        description="Автоматическая конвертация в TON",
    )
    print(f"Счёт: {invoice.amount} {invoice.asset}")
    print(f"После оплаты будет конвертировано в: {invoice.swap_to}")
    return invoice

Пример 4: Счёт с кастомной кнопкой

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

Python · Инвойс с кнопкой после оплаты
from aiosend import PaidBtnName

async def create_invoice_with_button():
    cp = CryptoPay(token="YOUR_TOKEN")
    invoice = await cp.create_invoice(
        amount=15,
        asset="USDT",
        description="Премиум-доступ на 1 месяц",
        paid_btn_name=PaidBtnName.OPENBOT,
        paid_btn_url="https://t.me/your_bot?start=premium_123",
        payload="premium_activation_user_123",
    )
    print(f"Счёт: {invoice.amount} {invoice.asset}")
    print(f"Кнопка: {invoice.paid_btn_name}")
    return invoice

Пример 5: Полный счёт со всеми параметрами

Максимальная конфигурация с большинством параметров.

Python · Максимальная конфигурация
async def create_full_invoice():
    cp = CryptoPay(token="YOUR_TOKEN")
    invoice = await cp.create_invoice(
        amount=99.99,
        fiat="USD",
        accepted_assets=["USDT", "TON", "BTC"],
        description="Подписка Premium на 1 год",
        hidden_message=(
            "Спасибо за покупку Premium!\n"
            "Код активации: PRM-2024-X9K2\n"
            "Ссылка: https://example.com/activate"
        ),
        paid_btn_name=PaidBtnName.VIEWITEM,
        paid_btn_url="https://example.com/dashboard",
        payload='{"user_id": 123, "plan": "premium_annual"}',
        allow_comments=False,
        allow_anonymous=False,
        expires_in=86400,
    )
    return invoice

Пример 6: Обработка ошибок при создании

Всегда обрабатывай возможные исключения.

Python · Обработка ошибок
from aiosend import CryptoPay
from aiosend.exceptions import APIError, MethodValuesError

async def create_invoice_safe():
    cp = CryptoPay(token="YOUR_TOKEN")
    try:
        invoice = await cp.create_invoice(
            amount=100,
            asset="USDT",
            expires_in=3600,
        )
        return invoice
    except MethodValuesError as e:
        print(f"Ошибка в параметрах: {e}")
    except APIError as e:
        print(f"Ошибка API: {e}")
    except Exception as e:
        print(f"Неожиданная ошибка: {e}")
    return None
⚠️

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

Минимальные и максимальные суммы

Каждый актив имеет свои ограничения по минимальной и максимальной сумме платежа. Например, для USDT минимальная сумма обычно 1 USDT, для TON — 0.1 TON, для BTC — 0.0001 BTC. Точные лимиты можно получить через метод get_currencies(), который возвращает min_amount и max_amount для каждой валюты. При попытке создать инвойс с суммой меньше минимальной API вернёт ошибку.

Ограничения по expires_in

expires_in принимает значения от 1 до 2 678 400 секунд (31 день). Если передать 0 или отрицательное число — API вернёт ошибку. Если передать значение больше 2678400 — API вернёт ошибку. Если не передавать expires_in вовсе — будет использован стандартный срок, установленный в Crypto Pay (обычно 2 часа, но может быть изменён администрацией).

Количество десятичных знаков

Для криптовалют количество знаков после запятой ограничено свойством decimals валюты. Например, USDT имеет 2 знака (можно 100.50), TON — 9 знаков, BTC — 8 знаков. При передаче количества знаков больше допустимого, aiosend автоматически округляет сумму. Рекомендуется передавать amount как строку для сохранения точности: amount="0.000001" вместо amount=0.000001 (из-за потенциальных проблем с float).

Лимит на количество активных инвойсов

Crypto Pay не документирует точный лимит на количество активных инвойсов, но рекомендуется не создавать миллионы неоплаченных счетов. Используй разумные сроки истечения (expires_in) и регулярно очищай просроченные инвойсы с помощью delete_invoice().

Совместимость asset и fiat

Нельзя одновременно указать asset и fiat. Нельзя также указать currency_type="crypto" вместе с fiat. API вернёт ошибку при противоречивых параметрах. Всегда указывай либо asset (крипто-счёт), либо fiat (фиатный счёт).

⚡

Синхронный вариант: SyncCryptoPay

Если ты работаешь в синхронном окружении (например, в простом скрипте или Flask-приложении), используй SyncCryptoPay:

Python · Синхронный create_invoice
from aiosend import SyncCryptoPay

cp = SyncCryptoPay(token="YOUR_TOKEN")
invoice = cp.create_invoice(amount=50, asset="USDT")
print(f"Счёт #{invoice.invoice_id}: {invoice.bot_invoice_url}")

# Все параметры те же, что и в асинхронной версии
invoice = cp.create_invoice(
    amount=100,
    fiat="USD",
    accepted_assets=["USDT", "TON"],
    description="Синхронный счёт",
)

Синхронный vs асинхронный

Выбор между CryptoPay (async) и SyncCryptoPay (sync) зависит от твоего проекта. Для ботов на aiogram/Pyrogram используй асинхронный вариант. Для простых скриптов или Flask — синхронный. Функционально они идентичны.

🌐

Создание инвойса через Network напрямую

В aiosend можно работать напрямую с классом Network, минуя CryptoPay. Это полезно, если ты используешь кастомную сессию или хочешь отправить запрос напрямую.

Python · create_invoice через Network
from aiosend import CryptoPay
from aiosend.network import Network

# Network доступен через cp.network
cp = CryptoPay(token="YOUR_TOKEN")
invoice = await cp.network.create_invoice(amount=0.1, asset="TON")

# Или напрямую
network = Network(token="YOUR_TOKEN")
invoice = await network.create_invoice(amount=25, asset="USDT")
📌

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

1️⃣
create_invoice() — основной метод. Принимает amount (обязательно) и до 13 опциональных параметров. Возвращает объект Invoice с 25+ полями.
2️⃣
Asset или fiat, но не оба. Всегда указывай только один тип валюты. currency_type выставляется автоматически.
3️⃣
accepted_assets — для fiat-счетов. Позволяет ограничить список криптовалют для оплаты.
4️⃣
swap_to — автоматическая конвертация. Позволяет получить оплату в другом активе.
5️⃣
hidden_message виден только после оплаты. payload не виден никогда.
6️⃣
paid_btn_name + paid_btn_url — кнопка после оплаты. Работают только в паре.
7️⃣
expires_in от 1 до 2 678 400 секунд (31 день). Без указания — стандартный срок Crypto Pay.
🎯

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

Задание: Создай скрипт для генерации инвойсов

Напиши функцию generate_invoice(), которая принимает тип счёта (crypto/fiat), сумму и валюту, а возвращает готовый инвойс с оптимальными настройками. Функция должна:

  • Принимать аргументы: invoice_type ("crypto" или "fiat"), amount, currency, description
  • Для crypto-счетов: устанавливать asset=currency, expires_in=3600 (1 час)
  • Для fiat-счетов: устанавливать fiat=currency, accepted_assets=["USDT", "TON"], expires_in=86400 (1 день)
  • Добавлять description, payload с ID заказа (генерировать случайный)
  • Обрабатывать исключения и возвращать None при ошибке
  • Выводить ссылки всех трёх типов (bot, mini_app, web_app)

Подсказка:

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

async def generate_invoice(
    invoice_type: str,
    amount: float,
    currency: str,
    description: str | None = None,
) -> Invoice | None:
    cp = CryptoPay(token="YOUR_TOKEN")
    order_id = random.randint(10000, 99999)

    try:
        if invoice_type == "crypto":
            invoice = await cp.create_invoice(
                amount=amount,
                asset=currency,
                description=description,
                payload=f"order_{order_id}",
                expires_in=3600,
            )
        elif invoice_type == "fiat":
            invoice = await cp.create_invoice(
                amount=amount,
                fiat=currency,
                accepted_assets=["USDT", "TON"],
                description=description,
                payload=f"order_{order_id}",
                expires_in=86400,
            )
        else:
            raise ValueError("Неверный тип счёта")

        print(f"✅ Счёт #{invoice.invoice_id} создан!")
        print(f"   Сумма: {invoice.amount} {invoice.asset or invoice.fiat}")
        print(f"   Статус: {invoice.status}")
        print(f"   Бот: {invoice.bot_invoice_url}")
        print(f"   Mini App: {invoice.mini_app_invoice_url}")
        print(f"   Web App: {invoice.web_app_invoice_url}")
        return invoice

    except MethodValuesError as e:
        print(f"❌ Ошибка параметров: {e}")
    except APIError as e:
        print(f"❌ Ошибка API: {e}")
    except Exception as e:
        print(f"❌ Неизвестная ошибка: {e}")

    return None

# Пример использования
async def main():
    await generate_invoice("crypto", 25, "USDT", "Тестовый товар")
    await generate_invoice("fiat", 50, "USD", "Премиум-доступ")

asyncio.run(main())

Урок 3.1: Создание инвойсов

10 вопросов