К основному содержанию
T TON Adoption
Кошельки DEV · 2026

Crypto Pay API: приём криптоплатежей в Telegram-боте за час

Практический гайд по Crypto Pay API от Crypto Bot: получение токена, createInvoice, проверка подписи webhook, поддерживаемые активы

Автор
TON Adoption Team · исследовательская группа проекта
Опубликовано
6 мин. чтения

Crypto Pay — HTTP API от Crypto Bot, через который Telegram-бот, сайт или мини-апп может принимать криптоплатежи в TON, USDT и ещё ~15 активах без своего бэкенд-кошелька, без интеграции с биржей и без on-chain инфраструктуры. На нём построены десятки тысяч мерчантов: магазины стикеров, подписки на боты, инфо-курсы, VPN-сервисы. В этом материале — практический сценарий «от нуля до production» для разработчика: получение токена, createInvoice, валидация webhook’ов, обработка ошибок и продакшен-чеклист.

Когда Crypto Pay — правильный выбор

  • Telegram-нативная аудитория. Пользователи уже держат баланс в @CryptoBot (десятки миллионов аккаунтов) — оплата в 1 клик, без копирования адресов.
  • Микро-платежи 1–50 USD. Подписки, виртуальные товары, чаевые, разовые услуги — там, где сетевые комиссии on-chain убивают экономику.
  • Не хочется держать собственный hot-wallet. Crypto Pay — кастодиальный, и для приёма платежей у тебя нет своего seed: ключи держит CG.
  • Нужна мульти-актив корзина. Один invoice можно сделать «принимаем TON или USDT или BTC» — выбор делает покупатель.

Шаг 1. Создаём приложение и получаем токен

  1. Открой @CryptoBot в Telegram (или короткую ссылку t.me/send).
  2. Меню → Crypto PayMy AppsCreate App.
  3. Дай приложению название (видно тебе и в логах операций).
  4. Бот выдаёт API-токен вида 12345:AAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. Сохрани его в секрет-стор (.env, Vault, AWS Secrets) — он эквивалент пароля к балансу приложения.

База URL’ов:

  • Production: https://pay.crypt.bot/api/
  • Testnet: https://testnet-pay.crypt.bot/api/ — отдельный токен, выпускается через @CryptoTestnetBot. Полезно для CI/staging.

Авторизация — заголовок Crypto-Pay-API-Token: <твой токен> в каждом запросе.

Шаг 2. Первый запрос — getMe

Проверь, что токен живой:

GET https://pay.crypt.bot/api/getMe
Crypto-Pay-API-Token: 12345:AAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Ответ:

{
  "ok": true,
  "result": {
    "app_id": 12345,
    "name": "My Test Shop",
    "payment_processing_bot_username": "CryptoBot"
  }
}

Если "ok": false — смотри error.code. Самые частые:

  • 401 UNAUTHORIZED — токен не совпадает (опечатка, скопировал с пробелом).
  • 400 USER_ID_INVALID — ошибка не из этого метода, но появляется при transfer с неправильным user_id.
  • 429 TOO_MANY_REQUESTS — лимит 100 запросов/секунду, добавь backoff.

Шаг 3. Создаём invoice

Базовый сценарий — пользователь хочет купить подписку «PRO» за $9.99 в USDT:

POST https://pay.crypt.bot/api/createInvoice
Content-Type: application/json
Crypto-Pay-API-Token: 12345:AAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

{
  "currency_type": "crypto",
  "asset": "USDT",
  "amount": "9.99",
  "description": "Подписка PRO, 30 дней",
  "hidden_message": "Спасибо! Бот активирует доступ в течение минуты.",
  "paid_btn_name": "openBot",
  "paid_btn_url": "https://t.me/your_bot?start=invoice_paid",
  "payload": "{\"user_id\":42,\"plan\":\"pro_30d\"}",
  "expires_in": 1800
}

Ответ:

{
  "ok": true,
  "result": {
    "invoice_id": 528347,
    "status": "active",
    "hash": "IVtN5sR1xVfH",
    "asset": "USDT",
    "amount": "9.99",
    "pay_url": "https://t.me/CryptoBot?start=IVtN5sR1xVfH",
    "bot_invoice_url": "https://t.me/CryptoBot?start=IVtN5sR1xVfH",
    "mini_app_invoice_url": "https://t.me/CryptoBot/app?startapp=IVtN5sR1xVfH",
    "web_app_invoice_url": "https://crypto-pay.io/invoice/...",
    "description": "Подписка PRO, 30 дней",
    "created_at": "2026-05-15T10:21:00Z",
    "expiration_date": "2026-05-15T10:51:00Z",
    "payload": "{\"user_id\":42,\"plan\":\"pro_30d\"}"
  }
}

Ключевые поля для интеграции:

  • pay_url — даёшь пользователю как кнопку «Оплатить». Открывает @CryptoBot с подгруженным invoice.
  • mini_app_invoice_url — для встраивания в Telegram Mini App (открывается прямо в боте без выхода).
  • payload — строка до 4096 символов, твоя «memo». Сюда положи user_id, order_id, любое что нужно вернуть в webhook’е. JSON-стрингифай — Crypto Pay не парсит.
  • expires_in — секунды до экспирации. По умолчанию invoice бессрочный; для микро-платежей советую 600–3600.

Multi-asset invoice

Хочешь дать выбор «TON или USDT»? Передай массив:

{
  "currency_type": "fiat",
  "fiat": "USD",
  "amount": "9.99",
  "accepted_assets": "TON,USDT,USDC",
  "description": "Подписка PRO, 30 дней",
  "payload": "..."
}

Crypto Pay сам конвертирует $9.99 в TON и USDT по текущему курсу на момент оплаты — покупатель выбирает кнопкой.

Шаг 4. Webhook на оплату

Crypto Pay не присылает webhook’и автоматически — их нужно включить отдельно. В @CryptoBot → My Apps → твоё приложение → Webhooks → задай URL вида https://api.example.com/cryptopay/webhook.

Формат входящего запроса:

POST /cryptopay/webhook
Content-Type: application/json
crypto-pay-api-signature: <hex-signature>

{
  "update_id": 7723,
  "update_type": "invoice_paid",
  "request_date": "2026-05-15T10:25:11Z",
  "payload": {
    "invoice_id": 528347,
    "status": "paid",
    "hash": "IVtN5sR1xVfH",
    "asset": "USDT",
    "amount": "9.99",
    "paid_amount": "9.99",
    "paid_asset": "USDT",
    "paid_fiat_rate": "1",
    "fee": "0",
    "paid_anonymously": false,
    "paid_btn_name": "openBot",
    "paid_btn_url": "https://t.me/your_bot?start=invoice_paid",
    "comment": null,
    "payload": "{\"user_id\":42,\"plan\":\"pro_30d\"}",
    "paid_at": "2026-05-15T10:25:05Z"
  }
}

Проверка подписи — обязательна

Подпись — HMAC-SHA-256 от сырого тела запроса с ключом, который сам тоже SHA-256 от твоего API-токена. На Node.js:

import crypto from 'node:crypto';

function verifyWebhook(rawBody, signature, apiToken) {
  const secret = crypto.createHash('sha256').update(apiToken).digest();
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature, 'hex'),
    Buffer.from(expected, 'hex'),
  );
}

На Python:

import hashlib
import hmac

def verify_webhook(raw_body: bytes, signature: str, api_token: str) -> bool:
    secret = hashlib.sha256(api_token.encode()).digest()
    expected = hmac.new(secret, raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(signature, expected)

Без этой проверки злоумышленник может прислать фальшивый POST с "status": "paid" и активировать заказ без оплаты. На этом «попадались» десятки магазинов в 2022–2024.

Идемпотентность

Crypto Pay при сбое доставки повторяет webhook несколько раз (с растущим backoff’ом). Это значит, что один и тот же update_id или invoice_id может прилететь дважды. Веди таблицу обработанных событий или просто проверяй статус заказа перед активацией:

if (await orderAlreadyFulfilled(invoiceId)) {
  return res.status(200).end(); // ack, но ничего не делаем
}
await fulfillOrder(invoiceId, payloadJson);
await markAsFulfilled(invoiceId);

Шаг 5. Polling как fallback

Если webhook не дошёл (твой сервер был в дауне), не теряй платёж — раз в N минут опрашивай getInvoices:

GET https://pay.crypt.bot/api/getInvoices?status=paid&offset=0&count=100
Crypto-Pay-API-Token: ...

Возвращает массив со всеми оплаченными invoice’ами. Сравни с локальной БД, добей пропущенные. Хорошая частота для cron — раз в 5 минут для активных заказов.

Поддерживаемые активы (2026)

На момент написания Crypto Pay принимает:

СетьАктивы
TONTON, USDT-TON, NOT, jUSDC, jUSDT, MAJOR, DOGS, HMSTR
BitcoinBTC
EthereumETH, USDT-ERC20, USDC-ERC20
TronUSDT-TRC20
BNB ChainBNB, USDT-BEP20
SolanaSOL, USDT-SPL
LitecoinLTC

Точный список меняется — запрашивай getCurrencies перед onboarding’ом мерчанта, чтобы UI не показывал отсутствующие активы.

Типовые ошибки и как их ловить

INVOICE_NOT_FOUND

Происходит при попытке вернуть getInvoices по invoice_id, который создан другим приложением (с другим токеном). Один токен видит только свои invoice’ы.

EXPIRES_IN_INVALID

expires_in должен быть от 1 до 2 678 400 (31 день). Если ставишь больше — invoice создаётся без экспирации, но при этом возвращается ошибка. Проверяй диапазон на стороне клиента.

Курс расходится с моментом оплаты

Если invoice в fiat ($9.99) с accepted_assets: TON,USDT, курс фиксируется на момент оплаты, не создания. При высокой волатильности это создаёт mini-arbitrage: пользователь может ждать выгодный момент. Для критичных позиций используй короткий expires_in (60–300 секунд).

Webhook прилетает без подписи

Признак фальшивки или старой версии Crypto Pay. Не доверяй запросам без crypto-pay-api-signature. С 2024 года все production webhook’и подписаны.

Безопасность приложения

  • Никогда не клади токен в фронтенд / клиентскую часть бота. Crypto Pay-токен = доступ к балансу. Только серверная сторона.
  • Используй HTTPS на webhook-endpoint’е. Без него подпись не спасает от MITM на роутере.
  • Логируй update_id каждого webhook’а — поможет при разборе споров и для cron-fallback.
  • Раздели приложения по средам. Production-токен — отдельно, staging — отдельный токен в testnet. Случайный refund с production-кошелька портит много нервов.
  • Включи 2FA в Telegram — компрометация аккаунта владельца приложения = компрометация баланса.

Альтернативы и комбинация

  • xRocket Pay — прямой конкурент, очень похожий API (createInvoice / webhook), отдельная база пользователей. Многие магазины интегрируют оба: пользователь выбирает «Crypto Bot или xRocket».
  • Telegram Stars — внутренняя валюта Telegram, не крипта. Подходит для цифрового контента в Telegram, но монетизация и payout — через Telegram, не через крипто-сеть.
  • Прямой on-chain через TON Connect — некастодиально, без зависимости от стороннего бота, но требует своего бэкенда и UX-работы. Имеет смысл для крупных мерчантов, у которых уже есть TON-инфраструктура.

Гибридная стратегия для production: Crypto Pay + xRocket Pay покрывает 90% Telegram-аудитории, прямой on-chain через TON Connect — для тех, кто не доверяет кастодиальным сервисам или платит крупные суммы.

Production-чеклист

Перед запуском в прод пройдись по этим пунктам:

  • Токен в .env / Vault, не закоммичен.
  • Webhook на HTTPS, подпись проверяется HMAC-SHA-256.
  • Идемпотентность по update_id или invoice_id.
  • Cron-fallback через getInvoices для пропущенных webhook’ов (раз в 5 минут).
  • Логи всех webhook’ов с raw body — для разбора споров.
  • expires_in выставлен (для fiat invoice’ов — короткий, 60–300с).
  • Retry’и на сетевые ошибки createInvoice с экспоненциальным backoff’ом.
  • Алёрт на падение баланса приложения ниже порога — чтобы не пропустить, что закончились средства для refund’ов.
  • Документация по работе с поддержкой @CryptoBot_Support для эскалаций.
  • Тест-сценарий через testnet с реальным @CryptoTestnetBot пройден.

Что в итоге

Crypto Pay API — минимально болезненный способ начать принимать криптоплатежи в Telegram-боте. От нуля до первого подтверждённого invoice’а реально дойти за пару часов: получить токен, написать createInvoice, поднять webhook-endpoint с проверкой подписи. Кастодиальная природа — главный trade-off: ты экономишь на инфраструктуре, но отдаёшь надёжность и регуляторные риски на сторону Crypto Bot.

Для пилотов и микро-магазинов это правильный выбор почти всегда. Для серьёзного оборота — комбинируй с прямым on-chain приёмом через TON Connect, чтобы не зависеть от одного шлюза.

Источники

  • help.crypt.bot/crypto-pay-api — официальная документация API, включая список методов и поля webhook’ов.
  • Crypto Pay testnet — отдельная среда для интеграционных тестов.
  • @CryptoBot — основной бот для управления приложениями.

Частые вопросы

Нет, для базовых лимитов аккаунта KYC не требуется — достаточно создать приложение в `@CryptoBot` через My Apps. Лимиты выше повышаются после верификации, но для пилотных интеграций и микро-магазинов первый месяц можно работать без неё.
Crypto Pay — кастодиальный, поддерживает реальные крипто-активы (TON, USDT, BTC и др.), payout идёт на внутренний баланс приложения. xRocket Pay — прямой конкурент, похожий API, отдельный пул пользователей. Telegram Stars — внутренняя валюта Telegram, не крипта; конвертация в TON односторонняя и с комиссиями платформы. Crypto Pay выигрывает там, где аудитория уже держит баланс в `@CryptoBot` (а это десятки миллионов аккаунтов).
Crypto Pay не разбивает invoice на части — он либо оплачен полностью, либо нет. Если пользователь перевёл больше суммы (что бывает редко, только при ручной отправке вне invoice flow), излишек зачисляется на его внутренний баланс, а invoice помечается paid. Безопаснее проверять не только статус, но и поле `paid_amount` в webhook'е.
Прямого refund в Crypto Pay API нет. Возврат делается ручным переводом с баланса приложения на @username покупателя — либо через интерфейс `@CryptoBot`, либо через метод `transfer` в API. Для коммерции стоит хранить связь invoice → telegram_user_id, чтобы знать, кому возвращать.
Обязательно. Подпись формируется как HMAC-SHA-256 от тела запроса с твоим API-токеном в качестве ключа и приходит в заголовке `crypto-pay-api-signature`. Без проверки подписи злоумышленник может прислать фейковый «paid»-webhook с поддельного IP и активировать заказ без оплаты.
Создание invoice и приём платежа — 0%. Комиссия появляется только при выводе на внешний кошелёк (стандартная сетевая комиссия — около 0.05 TON для TON-сети, ~1 USDT для USDT-TRC20) и при свопе между активами внутри бота (~0.9% обмена). Это делает Crypto Pay одним из самых дешёвых способов принимать крипту для микро-магазинов.

Похожие материалы