Skip to main content

mystars-faas

PyPI Python license

Official Python SDK for the MyStars FaaS API — buy Telegram Stars & Premium for any @username, paid in GRAM (ex TON) or USDT (TON).

Sync + async clients, exact-Decimal money, typed errors, automatic retries + idempotency, webhook verification, a retail-markup calculator, and dependency-free on-chain payload builders.

Compatible with FaaS API v2.0.0. Requires Python ≥ 3.9. Only runtime dependency: httpx.

📖 HTTP API reference — the REST endpoints this package wraps: mystars.tg/docs (interactive OpenAPI portal). Install + quickstart for every language: mystars.tg/docs/sdks. Every public function is documented below. Changelog: CHANGELOG.md.

🌐 What the API does and how to get started: Telegram Stars API for developers. Our consumer store: MyStars.tg — buy Telegram Stars & Premium with crypto.

Install

pip install mystars-faas

Keys are issued in the MyStars Telegram bot — open @my_stars_tg_bot, tap API access, copy your X-Api-Key.

Runnable examples live in examples/ (quickstart + webhook receiver).

Quick start

The client reads your key from the environment. Set it before running — export MYSTARS_API_KEY=faas_.... If you keep keys in a .env file, load it yourself (e.g. with python-dotenv — load_dotenv()); it is not a dependency of this SDK, so os.environ["MYSTARS_API_KEY"] alone won't read a .env.

payment_currency is required. ton is the native GRAM coin — not USDT; usdt_ton is USDT (TON). There is no default: a call without it raises TypeError, and the SDK rejects any other value before a request is sent.

import os
from mystars_faas import MyStarsClient

client = MyStarsClient.production(os.environ["MYSTARS_API_KEY"])

quote = client.get_pricing(type="stars", quantity=100, payment_currency="ton")
print("pay", quote.amount, quote.currency)

check = client.check_recipient("durov", type="stars")
if not check.eligible:
    raise SystemExit(check.telegram_message)
# check.indeterminate is True when the check couldn't decide and failed open, so
# `eligible` is a default, not a measurement. Treat it as "unknown", never as "yes":
# ordering is still safe (the order re-checks authoritatively), but don't tell the
# buyer the recipient is confirmed.

order = client.create_order(            # an Idempotency-Key is generated + reused on retry
    type="stars", recipient="durov", quantity=100, payment_currency="ton",
    callback_url="https://your-app.example.com/webhooks/mystars",
)
# Pay order.payment.amount to order.payment.pay_to_address with the comment order.payment.memo.
print(order.payment)

final = client.wait_for_order(order.order_id, on_update=lambda o: print("status:", o.status))
print("done:", final.status, final.purchase_tx)

Async

from mystars_faas import AsyncMyStarsClient

async with AsyncMyStarsClient.production(key) as client:
    quote = await client.get_pricing(type="premium", months=3, payment_currency="usdt_ton")
    async for order in client.aiter_orders(status="delivered"):
        ...

Webhooks

from mystars_faas import WebhookVerifier

verifier = WebhookVerifier(WEBHOOK_SECRET)
event = verifier.verify(raw_body, request.headers["X-Faas-Signature"])  # raises on bad signature
# event.order_id, event.status — dedup on order_id (delivery is at-least-once)

Handles the 24h "current,previous" rotation header automatically. FastAPI / Flask route factories live in mystars_faas.integrations.fastapi / .flask (install mystars-faas[fastapi] / [flask]).

Your own retail markup

from mystars_faas import apply_retail_markup

quote = client.get_pricing(type="stars", quantity=100, payment_currency="usdt_ton")
retail = apply_retail_markup(quote, margin_pct=15, pass_through_processing_fee=True)
print(retail.total)   # decimal string — exact (computed in Decimal), two-stage cent-ceil
print(retail.profit)  # decimal string — your gross margin

All RetailQuote money fields (total, profit, subtotal, …) are returned as decimal strings, not Decimal. For a usdt_ton quote, the markup needs the fee breakdown — if the quote came back with fee=None (a cold-FX /v1/pricing row), apply_retail_markup raises MyStarsValidationError; re-quote get_pricing(...) to obtain the fee block first.

Pay an order (non-custodial)

order.payment (a PaymentInstruction) is on the create_order result. From contract v1.15.0 an Order from get_order / iter_orders / wait_for_order carries it too, but only while the order is awaiting_payment — it is None otherwise, since a closed order offers no pay-to details — and always carries payment_currency. Pay payment.amount in payment.currency: Order.amount_ton is the order's GRAM price, which equals the amount due only for a ton order.

from mystars_faas import build_payment_request

req = build_payment_request(order.payment)   # a create_order(...) result, or an awaiting_payment Order
if req.ton_deeplink:           # a `ton` (GRAM) order: deeplink, QR payload, one TON Connect message
    print(req.ton_deeplink)
    print(req.ton_connect[0])
else:                          # a `usdt_ton` order: pass sender_address + jetton_wallet_address
    print(req.note)            # to get a signable TON Connect message; req.ton_connect is empty

The builders refuse to guess: an unknown currency, a payment block whose amount_units / asset / decimals / transfer contradict its currency, or a zero or negative amount raises MyStarsValidationError instead of producing a payable message.

Holds no keys. Errors are typed subclasses of MyStarsAPIError (RecipientIneligibleError, RateLimitedError, …); the client retries transient failures (network, timeout, 502/503/504, 500, general 429 — honoring Retry-After, including the HTTP-date form) automatically and idempotency-safely. A response body larger than 4 MB is rejected (response_too_large) instead of being buffered whole.

Errors

Class HTTP TS-SDK alias
MyStarsValidationError — (client-side) —
BadRequestError 400 —
AuthenticationError 401 UnauthorizedError
PermissionDeniedError 403 ForbiddenError
NotFoundError 404 —
ConflictError / IdempotencyConflictError / OrderNotCancellableError 409 —
RecipientIneligibleError 422 —
RateLimitedError 429 —
InternalServerError / ServiceUnavailableError 500 / 503 —
MyStarsTransportError / TimeoutError_ — (no response) —

UnauthorizedError and ForbiddenError are exported aliases of AuthenticationError / PermissionDeniedError so code written against the TypeScript SDK's names catches the same error.

CLI

mystars-faas --api-key "$MYSTARS_API_KEY" pricing --type stars --quantity 100 --currency ton
mystars-faas orders-create --type stars --recipient durov --quantity 100 --currency ton --pay

# Verify a webhook offline. Prefer the env var — a --secret on argv is visible in `ps`.
export MYSTARS_WEBHOOK_SECRET="…"
mystars-faas webhook-verify --body "$RAW_BODY" --signature "$X_FAAS_SIGNATURE"

webhook-verify reads the secret from MYSTARS_WEBHOOK_SECRET (preferred) or --secret; the env var wins when both are set, because a command-line --secret leaks via the process list and shell history.

Metadata

Release files for mystars-faas 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mystars-faas 0.2.0
File Size Uploaded
mystars_faas-0.2.0.tar.gz 45.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mystars-faas 0.2.0
File Interpreter ABI Platform
mystars_faas-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 97.0 kB

Release files / mystars_faas-0.2.0.tar.gz

Download URL mystars_faas-0.2.0.tar.gz
Size 45.4 kB
Tags Source
SHA-256 checksum
How to use checksums
5e37eafe4cb6be2c8daf8f646d7a4b3f349a9857b2f69065e9e717ec08aea92b
BLAKE2b-256 checksum
How to use checksums
f404b4d4f48d2f0c6c3869360ba3a26c6121141e618aef9e84f9b435c7bfb069
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release files / mystars_faas-0.2.0-py3-none-any.whl

Download URL mystars_faas-0.2.0-py3-none-any.whl
Size 51.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9377fb092f577b5b4797eb807ded8f2dd67871cc2fd84255ce87ed16a5aaec7b
BLAKE2b-256 checksum
How to use checksums
72a657f94d5099c17280b1736f6c29842b14ed6d51ae36060a6d917e31fd6038
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.12

2 release files

0.1.11

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page