TON deep-link
URL-схема `ton://...` для прямой передачи параметров операции в TON-кошелёк: адрес получателя, сумма, комментарий, опционально payload. Базовая UX-абстракция, объединяющая разные кошельки.
Синонимы: ton deep link, deeplink, deep link, ton://
TON deep-link — URL-схема ton://transfer/<address>?amount=<nano>&text=<message>. Когда пользователь кликает по такой ссылке, ОС открывает зарегистрированный TON-кошелёк (Tonkeeper, MyTonWallet, @Wallet и т.д.) с предзаполненной формой транзакции.
Базовые параметры
amount— в нано-TON (1 TON = 10^9 nano).text— комментарий (UTF-8, ≤ ~120 байт).bin— base64-payload для смарт-контракт-вызова (jetton-перевод, NFT-action и т.д.).expires— Unix-timestamp дедлайна.
Когда использовать
- Donation-ссылки, QR-коды для оффлайн-оплаты, payment-request в чате — самый простой и без-серверный способ.
- Альтернатива TON Connect для one-shot операций без долгой авторизации.
Ограничения
- Нельзя получить ответ от кошелька в браузере (это fire-and-forget) — для interactive-сценариев нужен TON Connect 2.x.
- На desktop без установленного TON-кошелька ссылка не открывается — фоллбек должен показать QR-код.
Примеры реальных ссылок
Простой перевод 1 TON с комментарием:
ton://transfer/EQAbc...XYZ?amount=1000000000&text=Hello%20TON
Jetton-перевод (USDT) — параметры собираются в bin, base64-url payload содержит сериализованный transfer#0f8a7ea5 (op-code), сумму в jetton-минимальных единицах и адрес назначения:
import { beginCell, toNano } from '@ton/core';
const payload = beginCell()
.storeUint(0x0f8a7ea5, 32) // op transfer
.storeUint(Date.now(), 64) // query_id
.storeCoins(toNano('10')) // amount
.storeAddress(destination) // recipient
.storeAddress(owner) // response destination
.storeBit(0) // no custom payload
.storeCoins(toNano('0.05')) // forward_ton_amount
.storeBit(0) // forward_payload null
.endCell();
const bin = payload.toBoc().toString('base64url');
const link = `ton://transfer/${jettonWallet}?amount=50000000&bin=${bin}`;
50_000_000 нано-TON (~$0.10) идут как фи на исполнение jetton-передачи — без этого сообщение «обанкротит» jetton-кошелёк.
Интеграция в Telegram-бота
Внутри бота кнопку с deep-link удобно собрать через InlineKeyboardButton.url:
const url = `ton://transfer/${address}?amount=${nanoAmount}&text=${encodeURIComponent(memo)}`;
bot.sendMessage(chatId, 'Оплатить заказ:', {
reply_markup: { inline_keyboard: [[{ text: '💎 Оплатить', url }]] },
});
Telegram на iOS до 10.5 не открывал произвольные ton:// — приходилось wrapping в https://app.tonkeeper.com/transfer/..., который сам редиректил на нативную схему. С 2024-2025 поддержка стабильна, но fallback на Tonkeeper-bridge URL до сих пор разумен для legacy-клиентов.
Безопасность и валидация
При парсинге deep-link на сайте/в боте обязательно:
- Проверить адрес — bounceable vs non-bounceable форма должна соответствовать типу контракта (jetton-wallet всегда bounceable, для wallet-V5 разрешена обе).
- Перевести
amountв человекочитаемый перед показом — иначе пользователь увидит1000000000и не поймёт, что это 1 TON. - Санитизировать
text— он может содержать unicode-spoofing (RTL-override, zero-width). - Не доверять
expires— кошелёк сам проверяет, но в UI сайта показывайте «до 15:42», а не сырую timestamp.
Связанные темы
- TON Connect — для интерактивных операций с ответом от кошелька.
- Jetton — формат payload для токен-перевода.
- Mini-app — встроенный UI, где deep-link уступает место TON Connect SDK.