feat: Add Fragment API for TON topups, Telegram Premium purchases, and Stars transactions

- Implemented Fragment API with methods for TON topups, Premium gifts, and Stars purchases.
- Created configuration management using environment variables.
- Added detailed README documentation for installation, configuration, and usage.
- Developed utility classes for API client, wallet linking, and transaction processing.
- Included example usage in main.py for easy demonstration of API functionalities.
- Updated requirements.txt with necessary dependencies.
This commit is contained in:
bohd4nx
2025-11-03 05:58:34 +08:00
commit 760c853acd
17 changed files with 963 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
# Fragment.com cookies - copy from browser after login (Header String format)
# IMPORTANT: Use quotes to prevent semicolons from being treated as comments
COOKIES = "your_fragment_cookies_here"
HASH =
# TON wallet seed phrase - 12 or 24 words separated by spaces
SEED =
# TON API key - get from https://tonconsole.com
API_KEY =
+25
View File
@@ -0,0 +1,25 @@
# Python
__pycache__/
*.pyc
*.pyo
*.pyd
.Python
# Virtual environments
.venv/
venv/
# IDE
.idea/
.vscode/
# Logs
logs/
*.log
# Environment variables
.env
# System files
.DS_Store
Thumbs.db
+180
View File
@@ -0,0 +1,180 @@
<div align="center">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" width="120" height="120" style="border-radius: 24px;"><defs><clipPath id="__lottie_element_2"><rect width="512" height="512" x="0" y="0"></rect></clipPath><clipPath id="__lottie_element_4"><path d="M0,0 L100,0 L100,100 L0,100z"></path></clipPath></defs><g clip-path="url(#__lottie_element_2)"><g clip-path="url(#__lottie_element_4)" style="display: block;" transform="matrix(5.119999885559082,0,0,5.119999885559082,0,0)" opacity="1"><g style="display: block;" transform="matrix(1.333299994468689,0,0,1.333299994468689,0,0)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill="rgb(30,40,51)" fill-opacity="1" d=" M47.31999969482422,5.619999885559082 C47.31999969482422,5.619999885559082 27.68000030517578,5.619999885559082 27.68000030517578,5.619999885559082 C15.5,5.619999885559082 5.619999885559082,15.5 5.619999885559082,27.68000030517578 C5.619999885559082,27.68000030517578 5.619999885559082,47.31999969482422 5.619999885559082,47.31999969482422 C5.619999885559082,59.5 15.5,69.37999725341797 27.68000030517578,69.37999725341797 C27.68000030517578,69.37999725341797 47.31999969482422,69.37999725341797 47.31999969482422,69.37999725341797 C59.5,69.37999725341797 69.37999725341797,59.5 69.37999725341797,47.31999969482422 C69.37999725341797,47.31999969482422 69.37999725341797,27.68000030517578 69.37999725341797,27.68000030517578 C69.37999725341797,15.5 59.5,5.619999885559082 47.31999969482422,5.619999885559082 C47.31999969482422,5.619999885559082 47.31999969482422,5.619999885559082 47.31999969482422,5.619999885559082z"></path></g><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill="rgb(255,255,255)" fill-opacity="1" d=" M36.349998474121094,32.79999923706055 C36.349998474121094,32.79999923706055 21.1299991607666,25.940000534057617 21.1299991607666,25.940000534057617 C20.020000457763672,25.450000762939453 20.389999389648438,23.790000915527344 21.600000381469727,23.790000915527344 C21.600000381469727,23.790000915527344 53.41999816894531,23.790000915527344 53.41999816894531,23.790000915527344 C54.630001068115234,23.790000915527344 54.9900016784668,25.440000534057617 53.880001068115234,25.940000534057617 C53.880001068115234,25.940000534057617 38.66999816894531,32.79999923706055 38.66999816894531,32.79999923706055 C37.939998626708984,33.130001068115234 37.09000015258789,33.130001068115234 36.36000061035156,32.79999923706055 C36.36000061035156,32.79999923706055 36.349998474121094,32.79999923706055 36.349998474121094,32.79999923706055z M56.81999969482422,30.06999969482422 C57.43000030517578,29.1200008392334 56.43000030517578,27.979999542236328 55.400001525878906,28.440000534057617 C55.400001525878906,28.440000534057617 40.72999954223633,35.13999938964844 40.72999954223633,35.13999938964844 C39.72999954223633,35.599998474121094 39.09000015258789,36.61000061035156 39.09000015258789,37.70000076293945 C39.09000015258789,37.70000076293945 39.09000015258789,53.810001373291016 39.09000015258789,53.810001373291016 C39.09000015258789,54.93000030517578 40.54999923706055,55.36000061035156 41.15999984741211,54.41999816894531 C41.15999984741211,54.41999816894531 56.810001373291016,30.06999969482422 56.810001373291016,30.06999969482422 C56.810001373291016,30.06999969482422 56.81999969482422,30.06999969482422 56.81999969482422,30.06999969482422z M19.600000381469727,28.440000534057617 C18.579999923706055,27.979999542236328 17.56999969482422,29.1200008392334 18.18000030517578,30.06999969482422 C18.18000030517578,30.06999969482422 33.84000015258789,54.43000030517578 33.84000015258789,54.43000030517578 C34.45000076293945,55.380001068115234 35.90999984741211,54.939998626708984 35.90999984741211,53.81999969482422 C35.90999984741211,53.81999969482422 35.90999984741211,37.70000076293945 35.90999984741211,37.70000076293945 C35.90999984741211,36.599998474121094 35.27000045776367,35.599998474121094 34.27000045776367,35.13999938964844 C34.27000045776367,35.13999938964844 19.59000015258789,28.450000762939453 19.59000015258789,28.450000762939453 C19.59000015258789,28.450000762939453 19.600000381469727,28.440000534057617 19.600000381469727,28.440000534057617z"></path></g></g></g></g></g></svg>
<h1 style="margin-top: 24px;">💎 Fragment API от @bohd4nx</h1>
<p style="font-size: 18px; margin-bottom: 24px;">
<b>Автоматизация пополнений TON, покупки Telegram Premium и Stars через Fragment.com</b>
</p>
[Сообщить об ошибке](https://github.com/bohd4nx/fragmentapi/issues) · [Запросить функцию](https://github.com/bohd4nx/fragmentapi/issues) · [**Донат TON**](https://app.tonkeeper.com/transfer/UQBUAa7KCx1ifmoEy6lF7j-822Dm_cE1j9SR7UWteu3jzukV)
</div>
---
## ✨ Возможности
- 💰 **Пополнение TON для рекламы** - Отправка TON для рекламных кампаний и покупки подарков (1-1,000,000,000 TON)
- 👑 **Подарки Telegram Premium** - Покупка Premium подписок(3, 6 или 12 месяцев)
-**Покупка Telegram Stars** - Покупка Stars для пользователей (50-1,000,000 Stars)
## 🚀 Быстрый старт
### 1. Установка
```bash
git clone https://github.com/bohd4nx/FragmentAPI.git
cd FragmentAPI
pip install -r requirements.txt
```
### 2. Настройка
Скопируйте пример конфигурации и отредактируйте:
```bash
cp .env.example .env
```
Отредактируйте файл `.env`:
```env
COOKIES = your_fragment_cookies_here
SEED = word1 word2 word3 ... word24
HASH = your_fragment_hash_here
API_KEY = your_ton_api_key_here
```
### 3. Получение необходимых данных
#### 🍪 Куки Fragment.com
**Предварительные требования**: Войдите в свой аккаунт Telegram и подключите TON кошелёк, который хотите использовать для платежей.
1. **Установите расширение Cookie Editor**:
- Скачайте из [Chrome Web Store](https://chromewebstore.google.com/detail/cookie-editor/hlkenndednhfkekhgcdicdfddnkalmdm)
- Добавьте расширение в ваш браузер
2. **Извлечение куки**:
- Откройте [Fragment.com](https://fragment.com) и убедитесь, что вы вошли в систему
- Полностью обновите страницу
- Нажмите на иконку расширения Cookie Editor
- Нажмите кнопку **"Export"**
- Выберите формат **"Header String"**
- Скопируйте результат → вставьте в `COOKIES` в вашем `.env` файле
- **Важно**: Заключите значение в кавычки, чтобы точки с запятой не интерпретировались как комментарии
**Ожидаемый формат**:
```env
COOKIES = "stel_token=<TOKEN>;stel_dt=<STEL_DT>;stel_ssid=<SSID>;stel_ton_token=<TON_TOKEN>"
```
#### 🔐 Seed-фраза TON кошелька
**Если у вас ещё нет TON кошелька**:
1. **Скачайте Tonkeeper**:
- iOS: [App Store](https://apps.apple.com/app/tonkeeper/id1587742107)
- Android: [Google Play](https://play.google.com/store/apps/details?id=com.ton_keeper)
2. **Создайте новый кошелёк**:
- Откройте приложение Tonkeeper
- Нажмите **"Создать новый кошелёк"**
- **ВАЖНО**: Запишите вашу 24-словную seed-фразу на бумаге
- Храните её в безопасном месте - никогда не делитесь ей ни с кем!
- Завершите настройку кошелька
3. **Получите вашу seed-фразу**:
- Если у вас уже есть кошелёк, перейдите в Настройки → Резервное копирование
- Введите ваш пароль
- Скопируйте 24 слова → вставьте в `SEED` в вашем `.env` файле
**Формат**: `слово1 слово2 слово3 ... слово24`
#### 🔗 Хеш Fragment
**Предварительные требования**: Сначала завершите настройку куки выше.
1. **Подключите кошелёк к Fragment**:
- Перейдите на [Fragment.com](https://fragment.com)
- Убедитесь, что ваш TON кошелёк подключён
- Войдите с вашим аккаунтом Telegram
2. **Извлечение хеша**:
- Откройте **Инструменты разработчика** (F12)
- Нажмите на вкладку **"Сеть"**
- Перейдите к [покупке Stars](https://fragment.com/stars/buy)
- Выберите получателя как **"Buy for myself"**
- Обновите страницу (Ctrl+R / Cmd+R)
- Найдите сетевые запросы, содержащие `?hash=`
- Найдите значение хеша и скопируйте его → вставьте в `HASH` в вашем `.env` файле
**Ожидаемый формат**: `?hash=<ваш_хеш_здесь>`
#### 🔑 API ключ TON
1. **Получите API ключ**:
- Посетите [TON Console](https://tonconsole.com)
- Создайте аккаунт и войдите
- Сгенерируйте новый API ключ
- Скопируйте ключ → вставьте в `API_KEY` в вашем `.env` файле
**Альтернатива**: Вы также можете использовать [TON API](https://tonapi.io) для получения API ключа.
### 4. Использование
#### Запуск примеров
```bash
python main.py
```
#### Программное использование
```python
from app.methods import FragmentTon, FragmentPremium, FragmentStars
# Пополнение TON для рекламы
ton_client = FragmentTon()
result = await ton_client.topup_ton("@username", 5)
# Покупка Premium
premium_client = FragmentPremium()
result = await premium_client.buy_premium("@username", 6)
# Покупка Stars
stars_client = FragmentStars()
result = await stars_client.buy_stars("@username", 50)
```
### Поддерживаемые операции
| Операция | Метод | Параметры | Ограничения |
| ------------------- | ------------------------------- | ---------------------------------- | ------------------- |
| **Пополнение TON** | `topup_ton(username, amount)` | Имя пользователя, количество TON | 1-1,000,000,000 TON |
| **Подарок Premium** | `buy_premium(username, months)` | Имя пользователя, длительность | 3, 6 или 12 месяцев |
| **Покупка Stars** | `buy_stars(username, amount)` | Имя пользователя, количество Stars | 50-1,000,000 Stars |
### Форматы имён пользователей
Все методы принимают различные форматы имён пользователей:
- `@username` (с @)
- `username` (без @)
<div align="center">
### Made with ❤️ by [@bohd4nx](https://t.me/bohd4nx)
**Поставьте ⭐ этому репозиторию, если он оказался полезным!**
</div>
+180
View File
@@ -0,0 +1,180 @@
<div align="center">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" width="120" height="120" style="border-radius: 24px;"><defs><clipPath id="__lottie_element_2"><rect width="512" height="512" x="0" y="0"></rect></clipPath><clipPath id="__lottie_element_4"><path d="M0,0 L100,0 L100,100 L0,100z"></path></clipPath></defs><g clip-path="url(#__lottie_element_2)"><g clip-path="url(#__lottie_element_4)" style="display: block;" transform="matrix(5.119999885559082,0,0,5.119999885559082,0,0)" opacity="1"><g style="display: block;" transform="matrix(1.333299994468689,0,0,1.333299994468689,0,0)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill="rgb(30,40,51)" fill-opacity="1" d=" M47.31999969482422,5.619999885559082 C47.31999969482422,5.619999885559082 27.68000030517578,5.619999885559082 27.68000030517578,5.619999885559082 C15.5,5.619999885559082 5.619999885559082,15.5 5.619999885559082,27.68000030517578 C5.619999885559082,27.68000030517578 5.619999885559082,47.31999969482422 5.619999885559082,47.31999969482422 C5.619999885559082,59.5 15.5,69.37999725341797 27.68000030517578,69.37999725341797 C27.68000030517578,69.37999725341797 47.31999969482422,69.37999725341797 47.31999969482422,69.37999725341797 C59.5,69.37999725341797 69.37999725341797,59.5 69.37999725341797,47.31999969482422 C69.37999725341797,47.31999969482422 69.37999725341797,27.68000030517578 69.37999725341797,27.68000030517578 C69.37999725341797,15.5 59.5,5.619999885559082 47.31999969482422,5.619999885559082 C47.31999969482422,5.619999885559082 47.31999969482422,5.619999885559082 47.31999969482422,5.619999885559082z"></path></g><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill="rgb(255,255,255)" fill-opacity="1" d=" M36.349998474121094,32.79999923706055 C36.349998474121094,32.79999923706055 21.1299991607666,25.940000534057617 21.1299991607666,25.940000534057617 C20.020000457763672,25.450000762939453 20.389999389648438,23.790000915527344 21.600000381469727,23.790000915527344 C21.600000381469727,23.790000915527344 53.41999816894531,23.790000915527344 53.41999816894531,23.790000915527344 C54.630001068115234,23.790000915527344 54.9900016784668,25.440000534057617 53.880001068115234,25.940000534057617 C53.880001068115234,25.940000534057617 38.66999816894531,32.79999923706055 38.66999816894531,32.79999923706055 C37.939998626708984,33.130001068115234 37.09000015258789,33.130001068115234 36.36000061035156,32.79999923706055 C36.36000061035156,32.79999923706055 36.349998474121094,32.79999923706055 36.349998474121094,32.79999923706055z M56.81999969482422,30.06999969482422 C57.43000030517578,29.1200008392334 56.43000030517578,27.979999542236328 55.400001525878906,28.440000534057617 C55.400001525878906,28.440000534057617 40.72999954223633,35.13999938964844 40.72999954223633,35.13999938964844 C39.72999954223633,35.599998474121094 39.09000015258789,36.61000061035156 39.09000015258789,37.70000076293945 C39.09000015258789,37.70000076293945 39.09000015258789,53.810001373291016 39.09000015258789,53.810001373291016 C39.09000015258789,54.93000030517578 40.54999923706055,55.36000061035156 41.15999984741211,54.41999816894531 C41.15999984741211,54.41999816894531 56.810001373291016,30.06999969482422 56.810001373291016,30.06999969482422 C56.810001373291016,30.06999969482422 56.81999969482422,30.06999969482422 56.81999969482422,30.06999969482422z M19.600000381469727,28.440000534057617 C18.579999923706055,27.979999542236328 17.56999969482422,29.1200008392334 18.18000030517578,30.06999969482422 C18.18000030517578,30.06999969482422 33.84000015258789,54.43000030517578 33.84000015258789,54.43000030517578 C34.45000076293945,55.380001068115234 35.90999984741211,54.939998626708984 35.90999984741211,53.81999969482422 C35.90999984741211,53.81999969482422 35.90999984741211,37.70000076293945 35.90999984741211,37.70000076293945 C35.90999984741211,36.599998474121094 35.27000045776367,35.599998474121094 34.27000045776367,35.13999938964844 C34.27000045776367,35.13999938964844 19.59000015258789,28.450000762939453 19.59000015258789,28.450000762939453 C19.59000015258789,28.450000762939453 19.600000381469727,28.440000534057617 19.600000381469727,28.440000534057617z"></path></g></g></g></g></g></svg>
<h1 style="margin-top: 24px;">💎 Fragment API by @bohd4nx</h1>
<p style="font-size: 18px; margin-bottom: 24px;">
<b>Automate TON topups, Telegram Premium purchases, and Stars transactions via Fragment.com</b>
</p>
[Report Bug](https://github.com/bohd4nx/fragmentapi/issues) · [Request Feature](https://github.com/bohd4nx/fragmentapi/issues) · [**Donate TON**](https://app.tonkeeper.com/transfer/UQBUAa7KCx1ifmoEy6lF7j-822Dm_cE1j9SR7UWteu3jzukV)
</div>
---
## ✨ Features
- 💰 **TON Advertisement Topups** - Send TON for advertising campaigns and purchasing gifts (1-1,000,000,000 TON)
- 👑 **Telegram Premium Gifts** - Purchase Premium subscriptions (3, 6, or 12 months)
-**Telegram Stars Purchases** - Buy Stars for users (50-1,000,000 Stars)
## 🚀 Quick Start
### 1. Installation
```bash
git clone https://github.com/bohd4nx/FragmentAPI.git
cd FragmentAPI
pip install -r requirements.txt
```
### 2. Configuration
Copy example configuration and edit:
```bash
cp .env.example .env
```
Edit `.env` file:
```env
COOKIES=your_fragment_cookies_here
SEED=word1 word2 word3 ... word24
HASH=your_fragment_hash_here
API_KEY=your_ton_api_key_here
```
### 3. Getting Required Data
#### 🍪 Fragment.com Cookies
**Prerequisites**: Login to your Telegram account and connect the TON wallet you want to use for payments.
1. **Install Cookie Editor Extension**:
- Download from [Chrome Web Store](https://chromewebstore.google.com/detail/cookie-editor/hlkenndednhfkekhgcdicdfddnkalmdm)
- Add extension to your browser
2. **Extract Cookies**:
- Open [Fragment.com](https://fragment.com) and ensure you're logged in
- Refresh the page completely
- Click on the Cookie Editor extension icon
- Click **"Export"** button
- Select **"Header String"** format
- Copy the result → paste to `COOKIES` in your `.env` file
- **Important**: Wrap the value in quotes to prevent semicolons from being treated as comments
**Expected format**:
```env
COOKIES = "stel_token=<TOKEN>;stel_dt=<STEL_DT>;stel_ssid=<SSID>;stel_ton_token=<TON_TOKEN>"
```
#### 🔐 TON Wallet Seed Phrase
**If you don't have a TON wallet yet**:
1. **Download Tonkeeper**:
- iOS: [App Store](https://apps.apple.com/app/tonkeeper/id1587742107)
- Android: [Google Play](https://play.google.com/store/apps/details?id=com.ton_keeper)
2. **Create New Wallet**:
- Open Tonkeeper app
- Tap **"Create New Wallet"**
- **IMPORTANT**: Write down your 24-word seed phrase on paper
- Store it securely - never share with anyone!
- Complete wallet setup
3. **Get Your Seed Phrase**:
- If you already have a wallet, go to Settings → Backup
- Enter your passcode
- Copy the 24 words → paste to `SEED` in your `.env` file
**Format**: `word1 word2 word3 ... word24`
#### 🔗 Fragment Hash
**Prerequisites**: Complete the cookies setup above first.
1. **Connect Wallet to Fragment**:
- Go to [Fragment.com](https://fragment.com)
- Ensure your TON wallet is connected
- Log in with your Telegram account
2. **Extract Hash**:
- Open **Developer Tools** (F12)
- Click on **"Network"** tab
- Navigate to [Fragment Stars Purchase](https://fragment.com/stars/buy)
- Select recipient as **"Buy for myself"**
- Refresh the page (Ctrl+R / Cmd+R)
- Look for network requests containing `?hash=`
- Find the hash value and copy it → paste to `HASH` in your `.env` file
**Expected format**: `?hash=<your_hash_here>`
#### 🔑 TON API Key
1. **Get API Key**:
- Visit [TON Console](https://tonconsole.com)
- Create account and login
- Generate new API key
- Copy the key → paste to `API_KEY` in your `.env` file
**Alternative**: You can also use [TON API](https://tonapi.io) for getting API key.
### 4. Usage
#### Run Examples
```bash
python main.py
```
#### Programmatic Usage
```python
from app.methods import FragmentTon, FragmentPremium, FragmentStars
# TON topup for ads
ton_client = FragmentTon()
result = await ton_client.topup_ton("@username", 5)
# Premium purchase
premium_client = FragmentPremium()
result = await premium_client.buy_premium("@username", 6)
# Stars purchase
stars_client = FragmentStars()
result = await stars_client.buy_stars("@username", 50)
```
### Supported Operations
| Operation | Method | Parameters | Limits |
| ------------------ | ------------------------------- | ---------------------- | ------------------- |
| **TON Topup** | `topup_ton(username, amount)` | Username, TON amount | 1-1,000,000,000 TON |
| **Premium Gift** | `buy_premium(username, months)` | Username, duration | 3, 6, or 12 months |
| **Stars Purchase** | `buy_stars(username, amount)` | Username, Stars amount | 50-1,000,000 Stars |
### Username Formats
All methods accept various username formats:
- `@username` (with @)
- `username` (without @)
<div align="center">
### Made with ❤️ by [@bohd4nx](https://t.me/bohd4nx)
**Star ⭐ this repo if you found it useful!**
</div>
+4
View File
@@ -0,0 +1,4 @@
__title__ = "Fragment API by @bohd4nx"
__version__ = "2025.1.1"
__author__ = "Bohdan (bohd4nx)"
__timestamp__ = "2025-11-03T12:00:00Z"
+3
View File
@@ -0,0 +1,3 @@
from app.core.config import Config
__all__ = ['Config']
+37
View File
@@ -0,0 +1,37 @@
import logging
import os
import sys
from typing import Dict
from dotenv import load_dotenv
load_dotenv(encoding='utf-8')
logger = logging.getLogger(__name__)
class Config:
def __init__(self):
required_keys = ['COOKIES', 'SEED', 'HASH', 'API_KEY']
missing_keys = []
self._config = {}
for key in required_keys:
value = os.getenv(key, '').strip()
if not value:
missing_keys.append(key)
self._config[key.lower()] = value
if missing_keys:
logger.error(f"Missing required environment variables: {', '.join(missing_keys)}")
logger.error("Create .env file based on .env.example and fill all fields")
sys.exit(1)
logger.info("Configuration loaded successfully")
def get_config(self) -> Dict[str, str]:
return self._config.copy()
def get(self, key: str, default: str = '') -> str:
return self._config.get(key, default)
+5
View File
@@ -0,0 +1,5 @@
from app.methods.premium import FragmentPremium
from app.methods.stars import FragmentStars
from app.methods.ton import FragmentTon
__all__ = ['FragmentTon', 'FragmentPremium', 'FragmentStars']
+120
View File
@@ -0,0 +1,120 @@
import base64
import logging
import re
import string
import time
import httpx
from tonutils.client import TonapiClient
from tonutils.wallet import WalletV5R1
from app.core.config import Config
from app.utils import TransactionProcessor, WalletLinker, ApiClient
logger = logging.getLogger(__name__)
class FragmentPremium:
def __init__(self):
config_reader = Config()
self.config = config_reader.get_config()
self.headers = {
'accept': 'application/json, text/javascript, */*; q=0.01',
'accept-encoding': 'gzip, deflate, br, zstd',
'accept-language': 'en-US,en;q=0.9,uk;q=0.8,ru;q=0.7',
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'cookie': self.config['cookies'],
'origin': 'https://fragment.com',
'referer': 'https://fragment.com/premium/buy',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
'x-requested-with': 'XMLHttpRequest'
}
self.transaction_processor = TransactionProcessor(self.config, self._clean_decode)
self.wallet_linker = WalletLinker(self.config, self.headers, self.transaction_processor)
self.api_client = ApiClient(self.config, self.headers, self.wallet_linker)
@staticmethod
def _clean_decode(s):
b = base64.b64decode(re.sub(r'[^A-Za-z0-9+/=]', '', s.strip()) + "=" * (-len(s) % 4))
t = next(
(b[i:].decode('utf-8', 'ignore') for i in range(20) if
b[i:].decode('utf-8', 'ignore').startswith("Telegram Premium")),
b.decode('utf-8', 'ignore')
)
return ''.join(c for c in t if c in string.printable or c in '\n\r\t ').strip()
async def _get_account_info(self):
client = TonapiClient(api_key=self.config['api_key'], is_testnet=False)
wallet, pub_key, _, _ = WalletV5R1.from_mnemonic(client=client, mnemonic=self.config['seed'])
boc = wallet.state_init.serialize().to_boc()
return {
"address": wallet.address.to_str(False, False),
"publicKey": pub_key.hex(),
"chain": "-239",
"walletStateInit": base64.b64encode(boc).decode()
}
async def buy_premium(self, username, months):
if months not in [3, 6, 12]:
return {"success": False, "error": "Invalid duration. Use 3, 6, or 12 months"}
account = await self._get_account_info()
async with httpx.AsyncClient() as client:
search_data = {"query": username, "months": months, "method": "searchPremiumGiftRecipient"}
search_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=search_data)
search_result = search_resp.json()
recipient = search_result.get("found", {}).get("recipient")
if not recipient:
return {"success": False, "error": "User not found"}
update_data = {"mode": "new", "lv": "false", "dh": str(int(time.time())), "method": "updatePremiumState"}
await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=update_data)
init_data = {"recipient": recipient, "months": months, "method": "initGiftPremiumRequest"}
init_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=init_data)
init_result = init_resp.json()
req_id = init_result.get("req_id")
if not req_id:
return {"success": False, "error": "Failed to initialize purchase"}
tx_data = {
'account': account,
'device': {"appVersion": "5.4.3", "platform": "iphone",
"features": ["SendTransaction", {"maxMessages": 255, "name": "SendTransaction"},
{"types": ["text", "binary", "cell"], "name": "SignData"}],
"appName": "Tonkeeper", "maxProtocolVersion": 2},
'transaction': 1,
'id': req_id,
'show_sender': 1,
'ref': "OprzztcdJ",
'method': 'getGiftPremiumLink'
}
request_success, transaction_result = await self.api_client.execute_transaction_request(tx_data, account)
if not request_success:
return transaction_result
success, error, tx_hash = await self.transaction_processor.process_transaction(transaction_result)
if success:
return {
"success": True,
"data": {
"transaction_id": tx_hash,
"username": username,
"months": months,
"timestamp": int(time.time())
}
}
return {"success": False, "error": error}
+109
View File
@@ -0,0 +1,109 @@
import base64
import logging
import re
import time
import httpx
from tonutils.client import TonapiClient
from tonutils.wallet import WalletV5R1
from app.core.config import Config
from app.utils import TransactionProcessor, WalletLinker, ApiClient
logger = logging.getLogger(__name__)
class FragmentStars:
def __init__(self):
config_reader = Config()
self.config = config_reader.get_config()
self.headers = {
'accept': 'application/json, text/javascript, */*; q=0.01',
'accept-encoding': 'gzip, deflate, br, zstd',
'accept-language': 'en-US,en;q=0.9,uk;q=0.8,ru;q=0.7',
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'cookie': self.config['cookies'],
'origin': 'https://fragment.com',
'referer': 'https://fragment.com/stars/buy',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
'x-requested-with': 'XMLHttpRequest'
}
self.transaction_processor = TransactionProcessor(self.config, self._clean_decode)
self.wallet_linker = WalletLinker(self.config, self.headers, self.transaction_processor)
self.api_client = ApiClient(self.config, self.headers, self.wallet_linker)
@staticmethod
def _clean_decode(s):
s = re.sub(r'[^A-Za-z0-9+/=]', '', s.strip())
b = base64.b64decode(s + "=" * (-len(s) % 4))
t = b.decode('utf-8', 'ignore')
m = re.search(r'(\d+\s+Telegram\s+Stars.*?Ref#[A-Za-z0-9]+)', t, re.S)
return m.group(1).strip() if m else t.strip()
async def _get_account_info(self):
client = TonapiClient(api_key=self.config['api_key'], is_testnet=False)
wallet, pub_key, _, _ = WalletV5R1.from_mnemonic(client=client, mnemonic=self.config['seed'])
boc = wallet.state_init.serialize().to_boc()
return {
"address": wallet.address.to_str(False, False),
"publicKey": pub_key.hex(),
"chain": "-239",
"walletStateInit": base64.b64encode(boc).decode()
}
async def buy_stars(self, username, amount):
if amount < 50:
return {"success": False, "error": "Minimum amount is 50 stars"}
account = await self._get_account_info()
async with httpx.AsyncClient() as client:
search_data = {"query": username, "quantity": "", "method": "searchStarsRecipient"}
search_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=search_data)
search_result = search_resp.json()
recipient = search_result.get("found", {}).get("recipient")
if not recipient:
return {"success": False, "error": "User not found"}
init_data = {"recipient": recipient, "quantity": amount, "method": "initBuyStarsRequest"}
init_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=init_data)
init_result = init_resp.json()
req_id = init_result.get("req_id")
if not req_id:
return {"success": False, "error": "Failed to initialize purchase"}
tx_data = {
'account': account,
'device': "iPhone15,2",
'transaction': 1,
'id': req_id,
'show_sender': 0,
'method': 'getBuyStarsLink'
}
request_success, transaction_result = await self.api_client.execute_transaction_request(tx_data, account)
if not request_success:
return transaction_result
success, error, tx_hash = await self.transaction_processor.process_transaction(transaction_result)
if success:
return {
"success": True,
"data": {
"transaction_id": tx_hash,
"username": username,
"amount": amount,
"timestamp": int(time.time())
}
}
return {"success": False, "error": error}
+115
View File
@@ -0,0 +1,115 @@
import base64
import logging
import re
import time
import httpx
from tonutils.client import TonapiClient
from tonutils.wallet import WalletV5R1
from app.core.config import Config
from app.utils import TransactionProcessor, WalletLinker, ApiClient
logger = logging.getLogger(__name__)
class FragmentTon:
def __init__(self):
config_reader = Config()
self.config = config_reader.get_config()
self.headers = {
'accept': 'application/json, text/javascript, */*; q=0.01',
'accept-encoding': 'gzip, deflate, br, zstd',
'accept-language': 'en-US,en;q=0.9,uk;q=0.8,ru;q=0.7',
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'cookie': self.config['cookies'],
'origin': 'https://fragment.com',
'referer': 'https://fragment.com/ads/topup',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
'x-requested-with': 'XMLHttpRequest'
}
self.transaction_processor = TransactionProcessor(self.config, self._clean_decode)
self.wallet_linker = WalletLinker(self.config, self.headers, self.transaction_processor)
self.api_client = ApiClient(self.config, self.headers, self.wallet_linker)
@staticmethod
def _clean_decode(s):
t = base64.b64decode(re.sub(r'[^A-Za-z0-9+/=]', '', s.strip()) + "=" * (-len(s) % 4)).decode('utf-8',
errors='ignore')
t = ''.join(c for c in t if c.isprintable() or c.isspace())
return t.lstrip("r0N").strip()
async def _get_account_info(self):
client = TonapiClient(api_key=self.config['api_key'], is_testnet=False)
wallet, pub_key, _, _ = WalletV5R1.from_mnemonic(client=client, mnemonic=self.config['seed'])
boc = wallet.state_init.serialize().to_boc()
return {
"address": wallet.address.to_str(False, False),
"publicKey": pub_key.hex(),
"chain": "-239",
"walletStateInit": base64.b64encode(boc).decode()
}
async def topup_ton(self, username, amount):
if amount < 1 or not isinstance(amount, int):
return {"success": False, "error": "Amount must be an integer >= 1 TON"}
account = await self._get_account_info()
async with httpx.AsyncClient() as client:
update_data = {"mode": "new", "method": "updateAdsTopupState"}
await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=update_data)
search_data = {"query": username, "method": "searchAdsTopupRecipient"}
search_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=search_data)
search_result = search_resp.json()
recipient = search_result.get("found", {}).get("recipient")
if not recipient:
return {"success": False, "error": "User not found"}
init_data = {"recipient": recipient, "amount": amount, "method": "initAdsTopupRequest"}
init_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=init_data)
init_result = init_resp.json()
req_id = init_result.get("req_id")
if not req_id:
return {"success": False, "error": "Failed to initialize topup"}
tx_data = {
'account': account,
'device': {"appVersion": "5.4.3", "platform": "iphone",
"features": ["SendTransaction", {"maxMessages": 255, "name": "SendTransaction"},
{"types": ["text", "binary", "cell"], "name": "SignData"}],
"appName": "Tonkeeper", "maxProtocolVersion": 2},
'transaction': 1,
'id': req_id,
'show_sender': 1,
'method': 'getAdsTopupLink'
}
request_success, transaction_result = await self.api_client.execute_transaction_request(tx_data, account)
if not request_success:
return transaction_result
success, error, tx_hash = await self.transaction_processor.process_transaction(transaction_result)
if success:
return {
"success": True,
"data": {
"transaction_id": tx_hash,
"username": username,
"amount": amount,
"timestamp": int(time.time())
}
}
return {"success": False, "error": error}
+5
View File
@@ -0,0 +1,5 @@
from .api_client import ApiClient
from .linkWallet import WalletLinker
from .transaction import TransactionProcessor
__all__ = ['TransactionProcessor', 'WalletLinker', 'ApiClient']
+27
View File
@@ -0,0 +1,27 @@
from typing import Dict, Any, Tuple
import httpx
class ApiClient:
def __init__(self, config: dict, headers: dict, wallet_linker):
self.config = config
self.headers = headers
self.wallet_linker = wallet_linker
async def execute_transaction_request(self, tx_data: Dict[str, Any], account: Dict[str, Any]) -> Tuple[
bool, Dict[str, Any]]:
async with httpx.AsyncClient() as client:
tx_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=tx_data)
transaction = tx_resp.json()
if transaction.get("need_verify"):
if not await self.wallet_linker.link_wallet(account):
return False, {"success": False, "error": "Failed to link wallet"}
tx_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=tx_data)
transaction = tx_resp.json()
return True, transaction
+31
View File
@@ -0,0 +1,31 @@
from typing import Dict, Any
import httpx
class WalletLinker:
def __init__(self, config: dict, headers: dict, transaction_processor):
self.config = config
self.headers = headers
self.transaction_processor = transaction_processor
async def link_wallet(self, account: Dict[str, Any]) -> bool:
async with httpx.AsyncClient() as client:
data = {
'account': account,
'device': "iPhone15,2",
'method': 'linkWallet'
}
response = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=data)
result = response.json()
if result.get("ok"):
return True
if "transaction" in result:
success, _, _ = await self.transaction_processor.process_transaction(result)
return success
return False
+36
View File
@@ -0,0 +1,36 @@
import logging
from typing import Tuple, Optional
from tonutils.client import TonapiClient
from tonutils.wallet import WalletV5R1
from tonutils.wallet.messages import TransferMessage
logger = logging.getLogger(__name__)
class TransactionProcessor:
def __init__(self, config: dict, clean_decode_func):
self.config = config
self._clean_decode = clean_decode_func
async def process_transaction(self, transaction_data: dict) -> Tuple[bool, Optional[str], Optional[str]]:
if "transaction" not in transaction_data or "messages" not in transaction_data["transaction"]:
return False, "Invalid transaction", None
client = TonapiClient(api_key=self.config['api_key'], is_testnet=False)
wallet, _, _, _ = WalletV5R1.from_mnemonic(client=client, mnemonic=self.config['seed'])
try:
message = transaction_data["transaction"]["messages"][0]
payload = self._clean_decode(message["payload"])
messages = [TransferMessage(
destination=message["address"],
amount=int(message["amount"]) / 1000000000,
body=payload
)]
tx_hash = await wallet.batch_transfer_messages(messages=messages)
return True, None, tx_hash
except Exception as e:
return False, str(e), None
+71
View File
@@ -0,0 +1,71 @@
import asyncio
import logging
from app.methods import FragmentTon, FragmentPremium, FragmentStars
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
async def topup_ton_example():
logger.info("Starting TON topup example")
ton_client = FragmentTon()
# @bohd4nx - target username, 5 - TON amount (integer 1-1000000000 (one billion))
result = await ton_client.topup_ton("@bohd4nx", 5)
if result["success"]:
data = result["data"]
logger.info(f"TON topup successful: {data['amount']} TON sent to {data['username']}")
logger.info(f"Transaction ID: {data['transaction_id']}")
else:
logger.error(f"TON topup failed: {result['error']}")
async def buy_premium_example():
logger.info("Starting Premium purchase example")
premium_client = FragmentPremium()
# @bohd4nx - target username, 6 - months duration (3, 6, or 12 only)
result = await premium_client.buy_premium("@bohd4nx", 6)
if result["success"]:
data = result["data"]
logger.info(f"Premium purchase successful: {data['months']} months sent to {data['username']}")
logger.info(f"Transaction ID: {data['transaction_id']}")
else:
logger.error(f"Premium purchase failed: {result['error']}")
async def buy_stars_example():
logger.info("Starting Stars purchase example")
stars_client = FragmentStars()
# @bohd4nx - target username, 50 - stars amount (integer 50-1000000 (one million))
result = await stars_client.buy_stars("@bohd4nx", 50)
if result["success"]:
data = result["data"]
logger.info(f"Stars purchase successful: {data['amount']} stars sent to {data['username']}")
logger.info(f"Transaction ID: {data['transaction_id']}")
else:
logger.error(f"Stars purchase failed: {result['error']}")
async def main():
logger.info("Starting Fragment API by @bohd4nx - examples")
await topup_ton_example()
await buy_premium_example()
await buy_stars_example()
logger.info("All examples completed")
if __name__ == "__main__":
logger.info("Fragment API by @bohd4nx - Usage Examples")
logger.info("Supported username formats: @username, username")
logger.info("Limits: TON minimum 1, Premium 3/6/12 months, Stars minimum 50")
logger.info("Setup: Copy .env.example to .env and fill all fields")
asyncio.run(main())
+4
View File
@@ -0,0 +1,4 @@
python-dotenv==1.2.1
asyncio==4.0.0
httpx==0.28.1
tonutils==0.5.3