mirror of
https://github.com/bohd4nx/FragmentAPI.git
synced 2026-07-25 06:14:29 +00:00
feat: add payment method options for purchases and giveaways, enhance documentation and examples
This commit is contained in:
@@ -7,6 +7,33 @@ and this project uses [Calendar Versioning](https://calver.org/) (`YYYY.MINOR.MI
|
||||
|
||||
---
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- `payment_method` option (`"ton"` / `"usdt_ton"`) for:
|
||||
- `purchase_stars()`
|
||||
- `purchase_premium()`
|
||||
- `giveaway_stars()`
|
||||
- `giveaway_premium()`
|
||||
|
||||
### Changed
|
||||
|
||||
- Added runtime validation for `payment_method` via `SUPPORTED_PAYMENT_METHODS` and `ConfigurationError.INVALID_PAYMENT_METHOD`
|
||||
- Updated method docstrings to explicitly document recipient/channel formats:
|
||||
- `@username` / `username` / `https://t.me/username`
|
||||
|
||||
### Tests
|
||||
|
||||
- Extended stars and premium test suites to cover:
|
||||
- invalid payment method
|
||||
- payment method propagation to `init*Request` payloads
|
||||
- accepted query formats (`@`, plain username, `t.me` link)
|
||||
|
||||
### Documentation
|
||||
|
||||
- Simplified `README` usage example
|
||||
|
||||
## [2026.2.1] — 2026-05-03
|
||||
|
||||
### Fixed
|
||||
@@ -48,37 +75,44 @@ and this project uses [Calendar Versioning](https://calver.org/) (`YYYY.MINOR.MI
|
||||
### Added
|
||||
|
||||
**Giveaways**
|
||||
|
||||
- `giveaway_stars(channel, winners, amount)` — Stars giveaway; 1–5 winners, 500–1 000 000 stars each
|
||||
- `giveaway_premium(channel, winners, months)` — Premium giveaway; 1–24 000 winners, 3/6/12 months each
|
||||
- `StarsGiveawayResult`, `PremiumGiveawayResult` result types
|
||||
|
||||
**Telegram Ads**
|
||||
|
||||
- `recharge_ads(account, amount)` — top up a Telegram Ads account; 1–1 000 000 000 TON
|
||||
- `AdsRechargeResult` result type
|
||||
|
||||
**Marketplace**
|
||||
|
||||
- `search_usernames(query?, sort?, filter?, offset_id?)` — search Fragment usernames; `sort`: `price_desc / price_asc / listed / ending`, `filter`: `auction / sale / sold`
|
||||
- `search_numbers(query?, sort?, filter?, offset_id?)` — search Fragment anonymous numbers; same `sort` / `filter` / pagination semantics
|
||||
- `search_gifts(query?, collection?, sort?, filter?, view?, attr?, offset?)` — search Fragment gifts; `attr` accepts `{"Model": ["Foosball"], "Backdrop": ["Celtic Blue"]}`
|
||||
- `UsernamesResult`, `NumbersResult`, `GiftsResult` result types
|
||||
|
||||
**Anonymous numbers**
|
||||
|
||||
- `get_login_code(number)` — fetch the current pending login code
|
||||
- `toggle_login_codes(number, can_receive)` — enable or disable login code delivery
|
||||
- `terminate_sessions(number)` — terminate all active Telegram sessions (two-step flow handled internally)
|
||||
- `LoginCodeResult`, `TerminateSessionsResult` result types; `AnonymousNumberError` exception
|
||||
|
||||
**Raw API**
|
||||
|
||||
- `FragmentClient.call(method, data, *, page_url)` — raw request to any Fragment API method
|
||||
- `FRAGMENT_BASE_URL` constant — base URL shared across all page constants and headers
|
||||
|
||||
**Examples**
|
||||
|
||||
- `examples/client/` — `wallet_info.py` (wallet info), `raw_api_call.py` (raw API call)
|
||||
- `examples/numbers/` — `manage_number.py` (login code fetch, session termination)
|
||||
- `examples/auctions/` — `search_usernames.py`, `search_numbers.py`, `search_gifts.py` (marketplace search with pagination)
|
||||
- `examples/purchase/` — `send_stars.py`, `send_premium.py`, `topup_ton_balance.py`, `run_stars_giveaway.py`, `run_premium_giveaway.py`, `recharge_ads_balance.py`
|
||||
|
||||
### Changed
|
||||
|
||||
- All result types now expose a unified `amount` field (`months` and `stars` removed)
|
||||
- `__repr__` includes the unit — `3 months`, `500 stars`, etc.
|
||||
- `timestamp` removed from all result dataclasses
|
||||
@@ -91,15 +125,18 @@ and this project uses [Calendar Versioning](https://calver.org/) (`YYYY.MINOR.MI
|
||||
## [2026.0.2] — 2026-03-20
|
||||
|
||||
### Added
|
||||
|
||||
- `timeout` parameter on `FragmentClient` (default `30.0` s) — passed through to every HTTP request
|
||||
|
||||
### Changed
|
||||
|
||||
- Cookie validation: narrowed type internally so no `# type: ignore` is needed in `FragmentClient.__init__`
|
||||
- `WALLET_CLASSES` typed as `dict[str, Any]` so mypy resolves `from_mnemonic` correctly
|
||||
- All four `examples/` files updated to `async with FragmentClient`, f-strings, and aligned error messages
|
||||
- README usage section rewritten with a single comprehensive `async with` example
|
||||
|
||||
### Fixed
|
||||
|
||||
- mypy: missing return path in `process_transaction` after retry loop
|
||||
- mypy: `cookies` union-attr error in `FragmentClient.__init__`
|
||||
|
||||
@@ -108,6 +145,7 @@ and this project uses [Calendar Versioning](https://calver.org/) (`YYYY.MINOR.MI
|
||||
## [2026.0.1] — 2026-03-16
|
||||
|
||||
### Added
|
||||
|
||||
- Initial stable release of `pyfragment`
|
||||
- `FragmentClient` — async client for the Fragment.com API with context manager support (`async with`)
|
||||
- `purchase_premium(username, months)` — purchase Telegram Premium for any user (3, 6, or 12 months)
|
||||
|
||||
@@ -4,15 +4,14 @@
|
||||
<h1 style="margin-top: 24px;">Fragment API</h1>
|
||||
|
||||
<p style="font-size: 18px; margin-bottom: 24px;">
|
||||
<b>Async Python client for the Fragment API — a unified toolkit to manage Telegram assets: purchase Stars and Premium, top up TON and Ads balances, run giveaways, manage anonymous numbers, and explore the marketplace for usernames, numbers, and gifts.</b>
|
||||
<b>Async Python client for the Fragment API. Buy Stars and Premium, top up TON and Ads balances, run giveaways, manage anonymous numbers, and search Fragment listings.</b>
|
||||
</p>
|
||||
|
||||
[](https://pypi.org/project/pyfragment/)
|
||||
[](https://pypi.org/project/pyfragment/)
|
||||
[](https://pepy.tech/projects/pyfragment)
|
||||
[](https://python.org)
|
||||
[](LICENSE)
|
||||
[](https://github.com/bohd4nx/pyfragment/stargazers)
|
||||
[](https://github.com/bohd4nx/pyfragment/actions)
|
||||
[](https://github.com/bohd4nx/pyfragment/actions)
|
||||
[](https://github.com/bohd4nx/pyfragment/blob/master/LICENSE)
|
||||
|
||||
[Report Bug](https://github.com/bohd4nx/pyfragment/issues) · [Request Feature](https://github.com/bohd4nx/pyfragment/issues) · [**Donate TON**](https://app.tonkeeper.com/transfer/UQCppfw5DxWgdVHf3zkmZS8k1mt9oAUYxQLwq2fz3nhO8No5)
|
||||
|
||||
@@ -75,22 +74,13 @@ Refresh when you get authentication errors.
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from pyfragment import (
|
||||
FragmentClient,
|
||||
FragmentError, # base — catches everything below
|
||||
UserNotFoundError, # username doesn't exist on Fragment
|
||||
WalletError, # insufficient balance or misconfiguration
|
||||
CookieError, # cookies are missing or expired
|
||||
TransactionError, # on-chain broadcast failed
|
||||
ConfigurationError, # invalid argument (months, amount, etc.)
|
||||
FragmentAPIError, # unexpected Fragment API response
|
||||
)
|
||||
from pyfragment import FragmentClient
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
async with FragmentClient(
|
||||
seed="word1 word2 ... word24", # 24-word TON wallet mnemonic
|
||||
api_key="YOUR_TONAPI_KEY", # from tonconsole.com
|
||||
seed="word1 word2 ... word24",
|
||||
api_key="YOUR_TONAPI_KEY",
|
||||
cookies={
|
||||
"stel_ssid": "...",
|
||||
"stel_dt": "...",
|
||||
@@ -98,40 +88,23 @@ async def main() -> None:
|
||||
"stel_ton_token": "...",
|
||||
},
|
||||
) as client:
|
||||
try:
|
||||
# Purchase 6 months of Telegram Premium
|
||||
result = await client.purchase_premium("@username", months=6)
|
||||
print(f"{result.amount} months of Premium successfully sent to {result.username} | tx: {result.transaction_id}")
|
||||
recipient = "https://t.me/username" # also supports: @username, username
|
||||
|
||||
# Purchase 500 Stars
|
||||
result = await client.purchase_stars("@username", amount=500)
|
||||
print(f"{result.amount} Stars successfully sent to {result.username} | tx: {result.transaction_id}")
|
||||
stars = await client.purchase_stars(recipient, amount=500, payment_method="usdt_ton")
|
||||
print(f"Stars sent: {stars.amount} to {stars.username} | tx: {stars.transaction_id}")
|
||||
|
||||
# Top up 10 TON to Telegram balance
|
||||
# wallet must hold at least amount + ~0.056 TON for gas
|
||||
result = await client.topup_ton("@username", amount=10)
|
||||
print(f"{result.amount} TON successfully sent to {result.username} | tx: {result.transaction_id}")
|
||||
|
||||
except UserNotFoundError:
|
||||
print(f"User was not found on fragment.com — check the username and try again.")
|
||||
except WalletError as e:
|
||||
print(f"Wallet error — insufficient balance or misconfiguration: {e}")
|
||||
except CookieError:
|
||||
print("Authentication failed — session cookies are missing or expired. Refresh them and retry.")
|
||||
except TransactionError as e:
|
||||
print(f"Transaction failed to broadcast on-chain: {e}")
|
||||
except ConfigurationError as e:
|
||||
print(f"Invalid argument: {e}")
|
||||
except FragmentAPIError as e:
|
||||
print(f"Unexpected response from Fragment API: {e}")
|
||||
except FragmentError as e:
|
||||
# catch-all for any other pyfragment error
|
||||
print(f"Unexpected error: {e}")
|
||||
premium = await client.purchase_premium(recipient, months=6, payment_method="ton")
|
||||
print(f"Premium sent: {premium.amount} months to {premium.username} | tx: {premium.transaction_id}")
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
Full runnable examples:
|
||||
|
||||
- https://github.com/bohd4nx/pyfragment/tree/master/examples
|
||||
- `examples/`
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
@@ -3,6 +3,8 @@ Example: run a Telegram Premium giveaway for a channel.
|
||||
|
||||
winners must be an integer between 1 and 24 000.
|
||||
months (Premium duration per winner) must be 3, 6, or 12.
|
||||
payment_method can be "ton" or "usdt_ton".
|
||||
Channel can be "@channel", "channel", or "https://t.me/channel".
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@@ -24,15 +26,21 @@ COOKIES = {
|
||||
"stel_ton_token": "YOUR_STEL_TON_TOKEN",
|
||||
}
|
||||
|
||||
CHANNEL = "@channel"
|
||||
CHANNEL = "https://t.me/channel"
|
||||
WINNERS = 10 # 1–24 000
|
||||
MONTHS = 3 # 3, 6 or 12
|
||||
PAYMENT_METHOD = "ton" # "ton" or "usdt_ton"
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
async with FragmentClient(seed=SEED, api_key=API_KEY, cookies=COOKIES) as client:
|
||||
try:
|
||||
result = await client.giveaway_premium(CHANNEL, winners=WINNERS, months=MONTHS)
|
||||
result = await client.giveaway_premium(
|
||||
CHANNEL,
|
||||
winners=WINNERS,
|
||||
months=MONTHS,
|
||||
payment_method=PAYMENT_METHOD,
|
||||
)
|
||||
except UserNotFoundError:
|
||||
print(f"Channel {CHANNEL} was not found on fragment.com — check the username and try again.")
|
||||
return
|
||||
|
||||
@@ -3,6 +3,8 @@ Example: run a Telegram Stars giveaway for a channel.
|
||||
|
||||
winners must be an integer between 1 and 5.
|
||||
amount (stars per winner) must be an integer between 500 and 1 000 000.
|
||||
payment_method can be "ton" or "usdt_ton".
|
||||
Channel can be "@channel", "channel", or "https://t.me/channel".
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@@ -24,15 +26,21 @@ COOKIES = {
|
||||
"stel_ton_token": "YOUR_STEL_TON_TOKEN",
|
||||
}
|
||||
|
||||
CHANNEL = "@channel"
|
||||
CHANNEL = "https://t.me/channel"
|
||||
WINNERS = 3 # 1–5
|
||||
AMOUNT = 1000 # 500–1 000 000 stars per winner
|
||||
PAYMENT_METHOD = "usdt_ton" # "ton" or "usdt_ton"
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
async with FragmentClient(seed=SEED, api_key=API_KEY, cookies=COOKIES) as client:
|
||||
try:
|
||||
result = await client.giveaway_stars(CHANNEL, winners=WINNERS, amount=AMOUNT)
|
||||
result = await client.giveaway_stars(
|
||||
CHANNEL,
|
||||
winners=WINNERS,
|
||||
amount=AMOUNT,
|
||||
payment_method=PAYMENT_METHOD,
|
||||
)
|
||||
except UserNotFoundError:
|
||||
print(f"Channel {CHANNEL} was not found on fragment.com — check the username and try again.")
|
||||
return
|
||||
|
||||
@@ -3,6 +3,8 @@ Example: purchase Telegram Premium for a user.
|
||||
|
||||
Supported durations: 3, 6, or 12 months.
|
||||
Set show_sender=False to send anonymously.
|
||||
payment_method can be "ton" or "usdt_ton".
|
||||
Username can be "@username", "username", or "https://t.me/username".
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@@ -24,14 +26,20 @@ COOKIES = {
|
||||
"stel_ton_token": "YOUR_STEL_TON_TOKEN",
|
||||
}
|
||||
|
||||
USERNAME = "@username"
|
||||
USERNAME = "https://t.me/username"
|
||||
MONTHS = 3 # 3, 6 or 12
|
||||
PAYMENT_METHOD = "ton" # "ton" or "usdt_ton"
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
async with FragmentClient(seed=SEED, api_key=API_KEY, cookies=COOKIES) as client:
|
||||
try:
|
||||
result = await client.purchase_premium(USERNAME, months=MONTHS, show_sender=True)
|
||||
result = await client.purchase_premium(
|
||||
USERNAME,
|
||||
months=MONTHS,
|
||||
show_sender=True,
|
||||
payment_method=PAYMENT_METHOD,
|
||||
)
|
||||
except UserNotFoundError:
|
||||
print(f"User {USERNAME} was not found on fragment.com — check the username and try again.")
|
||||
return
|
||||
|
||||
@@ -3,6 +3,8 @@ Example: purchase Telegram Stars for a user.
|
||||
|
||||
Amount must be an integer between 50 and 1 000 000.
|
||||
Set show_sender=False to send anonymously.
|
||||
payment_method can be "ton" or "usdt_ton".
|
||||
Username can be "@username", "username", or "https://t.me/username".
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@@ -24,14 +26,20 @@ COOKIES = {
|
||||
"stel_ton_token": "YOUR_STEL_TON_TOKEN",
|
||||
}
|
||||
|
||||
USERNAME = "@username"
|
||||
USERNAME = "https://t.me/username"
|
||||
AMOUNT = 500 # 50–1 000 000 stars
|
||||
PAYMENT_METHOD = "usdt_ton" # "ton" or "usdt_ton"
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
async with FragmentClient(seed=SEED, api_key=API_KEY, cookies=COOKIES) as client:
|
||||
try:
|
||||
result = await client.purchase_stars(USERNAME, amount=AMOUNT, show_sender=True)
|
||||
result = await client.purchase_stars(
|
||||
USERNAME,
|
||||
amount=AMOUNT,
|
||||
show_sender=True,
|
||||
payment_method=PAYMENT_METHOD,
|
||||
)
|
||||
except UserNotFoundError:
|
||||
print(f"User {USERNAME} was not found on fragment.com — check the username and try again.")
|
||||
return
|
||||
|
||||
@@ -136,7 +136,7 @@ class FragmentClient:
|
||||
"""Gift Telegram Premium to a user.
|
||||
|
||||
Args:
|
||||
username: Recipient's Telegram username (with or without ``@``).
|
||||
username: Recipient identifier — ``@username``, ``username``, or ``https://t.me/username``.
|
||||
months: Duration — ``3``, ``6``, or ``12``.
|
||||
show_sender: Show your name as the sender. Defaults to ``True``.
|
||||
payment_method: Payment currency — ``"ton"`` (default) or ``"usdt_ton"``.
|
||||
@@ -156,7 +156,7 @@ class FragmentClient:
|
||||
"""Send Telegram Stars to a user.
|
||||
|
||||
Args:
|
||||
username: Recipient's Telegram username (with or without ``@``).
|
||||
username: Recipient identifier — ``@username``, ``username``, or ``https://t.me/username``.
|
||||
amount: Number of stars — integer from ``50`` to ``1 000 000``.
|
||||
show_sender: Show your name as the gift sender. Defaults to ``True``.
|
||||
payment_method: Payment currency — ``"ton"`` (default) or ``"usdt_ton"``.
|
||||
@@ -211,7 +211,7 @@ class FragmentClient:
|
||||
"""Run a Telegram Stars giveaway for a channel.
|
||||
|
||||
Args:
|
||||
channel: Channel username (with or without ``@``).
|
||||
channel: Channel identifier — ``@channel``, ``channel``, or ``https://t.me/channel``.
|
||||
winners: Number of winners — integer from ``1`` to ``5``.
|
||||
amount: Stars each winner receives — integer from ``500`` to ``1 000 000``.
|
||||
payment_method: Payment currency — ``"ton"`` (default) or ``"usdt_ton"``.
|
||||
@@ -232,7 +232,7 @@ class FragmentClient:
|
||||
"""Run a Telegram Premium giveaway for a channel.
|
||||
|
||||
Args:
|
||||
channel: Channel username (with or without ``@``).
|
||||
channel: Channel identifier — ``@channel``, ``channel``, or ``https://t.me/channel``.
|
||||
winners: Number of winners — positive integer.
|
||||
months: Premium duration per winner — ``3``, ``6``, or ``12``. Defaults to ``3``.
|
||||
payment_method: Payment currency — ``"ton"`` (default) or ``"usdt_ton"``.
|
||||
|
||||
@@ -30,7 +30,7 @@ async def giveaway_premium(
|
||||
|
||||
Args:
|
||||
client: Authenticated :class:`FragmentClient` instance.
|
||||
channel: Channel username (with or without ``@``).
|
||||
channel: Channel identifier — ``@channel``, ``channel``, or ``https://t.me/channel``.
|
||||
winners: Number of winners — integer from ``1`` to ``24 000``.
|
||||
months: Premium duration per winner — ``3``, ``6``, or ``12``. Defaults to ``3``.
|
||||
payment_method: Payment currency — ``"ton"`` (default) or ``"usdt_ton"``.
|
||||
|
||||
@@ -30,7 +30,7 @@ async def giveaway_stars(
|
||||
|
||||
Args:
|
||||
client: Authenticated :class:`FragmentClient` instance.
|
||||
channel: Channel username (with or without ``@``).
|
||||
channel: Channel identifier — ``@channel``, ``channel``, or ``https://t.me/channel``.
|
||||
winners: Number of winners — integer from ``1`` to ``5``.
|
||||
amount: Stars each winner receives — integer from ``500`` to ``1 000 000``.
|
||||
payment_method: Payment currency — ``"ton"`` (default) or ``"usdt_ton"``.
|
||||
|
||||
@@ -31,7 +31,7 @@ async def purchase_premium(
|
||||
|
||||
Args:
|
||||
client: Authenticated :class:`FragmentClient` instance.
|
||||
username: Recipient's Telegram username (with or without ``@``).
|
||||
username: Recipient identifier — ``@username``, ``username``, or ``https://t.me/username``.
|
||||
months: Premium duration — ``3``, ``6``, or ``12``.
|
||||
show_sender: Show your name as the gift sender. Defaults to ``True``.
|
||||
payment_method: Payment currency — ``"ton"`` (default) or ``"usdt_ton"``.
|
||||
|
||||
@@ -27,7 +27,7 @@ async def purchase_stars(
|
||||
|
||||
Args:
|
||||
client: Authenticated :class:`FragmentClient` instance.
|
||||
username: Recipient's Telegram username (with or without ``@``).
|
||||
username: Recipient identifier — ``@username``, ``username``, or ``https://t.me/username``.
|
||||
amount: Number of Stars to send — integer from ``50`` to ``1 000 000``.
|
||||
show_sender: Show your name as the gift sender. Defaults to ``True``.
|
||||
payment_method: Payment currency — ``"ton"`` (default) or ``"usdt_ton"``.
|
||||
|
||||
+12
-8
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
|
||||
[project]
|
||||
name = "pyfragment"
|
||||
version = "2026.2.1"
|
||||
description = "Async Python client for the Fragment API — a unified toolkit to manage Telegram assets: purchase Stars and Premium, top up TON and Ads balances, run giveaways, manage anonymous numbers, and explore the marketplace for usernames, numbers, and gifts."
|
||||
description = "Async Python client for the Fragment API. Buy Stars and Premium, top up TON and Ads balances, run giveaways, manage anonymous numbers, and search Fragment listings."
|
||||
readme = "README.md"
|
||||
license = { text = "MIT" }
|
||||
requires-python = ">=3.10"
|
||||
@@ -14,19 +14,23 @@ keywords = [
|
||||
"fragment",
|
||||
"fragment-api",
|
||||
"telegram",
|
||||
"telegram-api",
|
||||
"telegram-stars",
|
||||
"telegram-premium",
|
||||
"telegram-giveaway",
|
||||
"telegram-ads",
|
||||
"ton",
|
||||
"ton-blockchain",
|
||||
"tonkeeper",
|
||||
"tonapi",
|
||||
"crypto",
|
||||
"blockchain",
|
||||
"anonymous-numbers",
|
||||
"username-auctions",
|
||||
"gift-marketplace",
|
||||
"crypto-payments",
|
||||
"nft-marketplace",
|
||||
"web3",
|
||||
"giveaway",
|
||||
"anonymous-number",
|
||||
"username",
|
||||
"nft",
|
||||
"async",
|
||||
"python-client",
|
||||
"typed",
|
||||
"asyncio",
|
||||
]
|
||||
classifiers = [
|
||||
|
||||
Reference in New Issue
Block a user