# istars.uz — Telegram Stars & Telegram Premium API > istars.uz is a REST API that resells Telegram Stars and gifts Telegram Premium via Fragment.com. Each client ("project") pays from its own project-owned TON wallet, either in native TON ("gram") or in USDT (a jetton on TON); a platform service fee is bundled automatically into the very same on-chain transaction as the purchase. This file follows the llms.txt convention (https://llmstxt.org/) so AI agents and LLMs can integrate with the API directly, without parsing the HTML docs page. Base URL: https://istars.uz All responses are JSON. Human-readable docs (Uzbek/Russian/English, with the same content plus a live UI): https://istars.uz/api-docs Current server mode: LIVE — send-stars/send-premium perform real Fragment purchases and broadcast real, irreversible TON transactions. Current service fee: 1.7% of every successful purchase (see "Service fee" below). ## Authentication Every /api/* endpoint (except /api/health, which needs no key at all) accepts a per-project API key through **two interchangeable methods, supported identically on every single endpoint below** — send-stars, send-premium, balance/wallet-balance, stars-price, max-stars, search-user: 1. HTTP header (recommended): `X-API-Key: ` 2. Query string or POST field: `api_key=` Use whichever is more convenient for your client — both are first-class, both are checked on the server by the exact same code path (`App\Api\ApiAuth::resolveProject()`), so there is no endpoint where only one of them works and no endpoint where behavior differs between them. If you happen to send both on the same request, the header takes precedence and the query/body value is ignored. Method 1 — header (works on GET and POST alike): curl -H "X-API-Key: YOUR_KEY" "https://istars.uz/api/balance" Method 2 — query string (works even from a plain browser address bar, or tools that can't set custom headers): curl "https://istars.uz/api/balance?api_key=YOUR_KEY" Method 2 also works as a POST form field for the write endpoints (send-stars/send-premium), e.g. `curl -X POST https://istars.uz/api/send-stars -d "api_key=YOUR_KEY&username=@x&quantity=100"`. To get a key: register at https://istars.uz/register (or log in at https://istars.uz/login), create a project on the dashboard, configure its wallet (generate a platform wallet or paste your own seed phrase), and copy the API key shown on the project page. Each project has its own isolated wallet, order history and daily limits; one account can own several projects. A missing or invalid key (by either method) returns `401 {"success":false,"error":"unauthorized","message":"..."}` — the response is identical regardless of which auth method was used or failed. ## Endpoints ### POST /api/send-stars (aliases: /api/sendStars — GET also works, params as query string) Buys and sends `quantity` Telegram Stars to `username`, paid from the project wallet. Params (JSON body, form field, or query string): username string required Telegram username of the recipient, with or without a leading @ quantity integer required 50 to 10,000,000 payment_method string optional "gram" (default, pay in TON) or "usdt" (pay in USDT) Example — header auth: curl -X POST https://istars.uz/api/send-stars \ -H "X-API-Key: YOUR_KEY" -H "Content-Type: application/json" \ -d '{"username":"@username","quantity":100,"payment_method":"usdt"}' Example — query-param auth (same request, same result): curl -X POST "https://istars.uz/api/send-stars?api_key=YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"@username","quantity":100,"payment_method":"usdt"}' Success (200): {"success":true,"dry_run":false,"username":"username","amount":100,"transaction_id":"..."} If the blockchain confirmation is still pending when the request returns, you instead get: {"success":true,"pending":true,"dry_run":false,"transaction_id":"...","message":"..."} Treat `pending:true` as "submitted, check back later" — not a failure. Extra error: `404 user_not_found` — recipient can't be found or can't receive a Stars gift on Fragment. ### POST /api/send-premium (aliases: /api/sendPremium — GET also works) Gifts `months` of Telegram Premium to `username`, paid from the project wallet. Same auth, wallet, fee and pending-state behavior as send-stars — kept as a fully separate endpoint/engine so a Premium issue can never affect Stars purchases. Params: username string required Telegram username, with or without @ months integer required 3, 6, or 12 (Fragment's only valid Premium gift durations) payment_method string optional "gram" (default) or "usdt" Example — header auth: curl -X POST https://istars.uz/api/send-premium \ -H "X-API-Key: YOUR_KEY" -H "Content-Type: application/json" \ -d '{"username":"@username","months":3}' Example — query-param auth (same request, same result): curl -X POST "https://istars.uz/api/send-premium?api_key=YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"@username","months":3}' Success (200): {"success":true,"dry_run":false,"username":"username","months":3,"transaction_id":"..."} Extra errors: `404 user_not_found`, and `400 already_subscribed` — the recipient already has Telegram Premium and can't receive another gift right now. ### GET /api/balance (alias: /api/wallet-balance) Returns the project wallet's address and current balances. Auth only, no other params. curl -H "X-API-Key: YOUR_KEY" "https://istars.uz/api/balance" curl "https://istars.uz/api/balance?api_key=YOUR_KEY" {"success":true,"address":"UQ...","wallet_version":"v5r1","gram_balance":1.2345,"usdt_balance":3.5} ### GET /api/stars-price Live Fragment price quote for `quantity` Stars, in TON or USDT — use it to show or confirm a price before calling send-stars, or just to poll current rates. No recipient is required; this is a generic quote. Params: quantity integer optional default 50 payment_method string optional "gram" (default) or "usdt" curl -H "X-API-Key: YOUR_KEY" "https://istars.uz/api/stars-price?quantity=100&payment_method=usdt" curl "https://istars.uz/api/stars-price?api_key=YOUR_KEY&quantity=100&payment_method=usdt" {"success":true,"quantity":100,"payment_method":"usdt","price":1.5,"currency":"USDT"} ### GET /api/max-stars Computes how many Stars the project's current wallet balance can afford, using a live Fragment rate and accounting for the service fee. Params: payment_method string optional "gram" (default) or "usdt" curl -H "X-API-Key: YOUR_KEY" "https://istars.uz/api/max-stars?payment_method=gram" curl "https://istars.uz/api/max-stars?api_key=YOUR_KEY&payment_method=gram" {"success":true,"payment_method":"gram","rate_per_star":0.010086,"currency":"TON","max_stars":4820,"gram_balance":48.912} When payment_method=usdt, the response has `usdt_balance` and `gram_balance_for_gas` instead of `gram_balance` — USDT transfers still need a small TON reserve to pay gas. ### GET /api/search-user Checks whether a Telegram username can receive a Stars gift AND, independently, whether it can receive a Premium gift on Fragment — WITHOUT sending anything, spending any funds, or building a transaction. Use this before send-stars/send-premium to validate a recipient cheaply (it's two read-only Fragment lookups, much lighter than stars-price, which also computes a price). This is the *only* endpoint that turns "user not found"/"already has Premium" into a normal 200 response instead of a 404/400 error — see below. Params (query string, form field, or JSON body): username string required Telegram username of the recipient, with or without a leading @ Example — header auth: curl -H "X-API-Key: YOUR_KEY" "https://istars.uz/api/search-user?username=durov" Example — query-param auth (same request, same result): curl "https://istars.uz/api/search-user?api_key=YOUR_KEY&username=durov" Success, recipient can receive both gifts (200): {"success":true,"username":"durov","can_receive_stars":true,"recipient_name":"Pavel Durov","reason":null,"can_receive_premium":true,"premium_reason":null} Success, recipient can NOT receive one or both gifts (still 200 — this is not an error): {"success":true,"username":"someunknownname123","can_receive_stars":false,"recipient_name":null,"reason":"not_found","can_receive_premium":false,"premium_reason":"not_found"} {"success":true,"username":"somechannel","can_receive_stars":false,"recipient_name":null,"reason":"not_a_user","can_receive_premium":false,"premium_reason":"not_a_user"} {"success":true,"username":"alreadypro","can_receive_stars":true,"recipient_name":"Some User","reason":null,"can_receive_premium":false,"premium_reason":"already_subscribed"} `reason` (Stars eligibility) is one of: null can_receive_stars is true — safe to call send-stars for this username "not_found" no such Telegram account is known to Fragment (typo, or the account never opened Fragment) "not_a_user" the username belongs to a channel/bot/group, which can't receive a personal Stars gift `premium_reason` (Premium eligibility) is one of: null can_receive_premium is true — safe to call send-premium for this username "not_found" same as above "not_a_user" same as above "already_subscribed" the recipient already has Telegram Premium and can't receive another gift right now The two flags are independent — check whichever one(s) matter for the gift you're about to send. Always branch on `can_receive_stars`/`can_receive_premium`, not HTTP status — this endpoint only returns a non-200 status for real errors (bad `username` shape, auth failure, Fragment being down), never for "the user doesn't exist" or "already has Premium", which are expected, normal outcomes here. ### GET /api/health — no auth required curl "https://istars.uz/api/health" {"success":true,"status":"ok","database":true,"dry_run":false} ## Error codes Every error response has the shape: `{"success":false,"error":"","message":"..."}` HTTP code meaning 401 unauthorized missing or invalid X-API-Key 422 invalid_username username missing, or not 5-32 chars of [a-zA-Z0-9_] 422 invalid_quantity quantity outside 50-10,000,000 (send-stars) 422 invalid_months months not one of 3 / 6 / 12 (send-premium) 422 invalid_payment_method payment_method not "gram" or "usdt" 429 rate_limited too many requests from this IP — see Rate limits 404 user_not_found recipient not found / can't receive this gift on Fragment 400 already_subscribed recipient already has Premium (send-premium only) 400 verification_required the platform's Fragment session needs re-verification — contact support, not solvable client-side 400 config_error wallet not configured for this project, or a request/daily limit was exceeded (see message for details) 400 fragment_error Fragment.com itself returned an error for this request 500 internal_error unexpected server-side failure Note: /api/search-user is the one exception — a nonexistent/ineligible recipient is reported as `200 {"success":true,"can_receive_stars":false,"reason":"not_found"|"not_a_user","can_receive_premium":false,"premium_reason":"not_found"|"not_a_user"|"already_subscribed"}`, not as a 404/400. It only returns an error status for a malformed `username`, missing/invalid auth, or a genuine Fragment/server failure. ## Rate & volume limits - Per-IP rate limit: 20 requests / 60s on send-stars and send-premium → 429 rate_limited above that. - Per-request cap: up to 5000 Stars per single send-stars call. - Per-project daily cap: 50000 Stars/day and 120 Premium-months/day, tracked per project (live mode only; resets daily on the server date). - Exceeding a cap returns `config_error` with the current usage spelled out in `message`. ## Service fee A 1.7% platform fee is withheld automatically from every successful purchase — you never calculate or send it yourself. It is bundled into the exact same signed on-chain transaction as the purchase (purchase and fee either both succeed or both fail — no partial charge is possible). If payment_method=gram the fee is collected in TON; if payment_method=usdt the fee is collected in USDT. Fund the project wallet for price + fee, not just the sticker price — /api/stars-price and /api/max-stars already factor the fee in. ## Integration notes for agents - Both GET and POST work on every /api/* route. Use POST with a JSON body for send-stars/send-premium in production; GET (all params in the query string) is convenient for quick manual testing. - A project's wallet must be configured (seed phrase saved, or a platform-generated wallet created) at https://istars.uz/dashboard before send-stars/send-premium will work — otherwise you get `config_error` ("wallet not configured"). - If the server is running in DRY-RUN mode, send-stars/send-premium return realistic success responses without touching Fragment or the blockchain — good for integration testing without spending real funds. Always check the `dry_run` field on the response rather than assuming. - Requests against the same project's wallet are serialized server-side — a TON wallet can only sign one transaction at a time (seqno ordering) — so concurrent send-stars/send-premium calls for the *same* project queue up rather than racing. Calls for *different* projects run independently. - Usernames are accepted with or without a leading "@" in every endpoint. - `/api/wallet-balance` and `/api/balance` are the same endpoint (alias); `/api/sendStars`/`/api/sendPremium` (camelCase) are aliases of `/api/send-stars`/`/api/send-premium`. - Call /api/search-user before send-stars/send-premium whenever the recipient is user-supplied or unverified — it costs two lightweight Fragment lookups (one per gift type) and lets you show a clear "user not found" / "already has Premium" message up front instead of discovering it from a 404/400 on send-stars/send-premium after the request has already gone through rate limiting and validation. It never spends funds or touches the blockchain, so it's always safe to call, including in DRY-RUN and LIVE mode alike. ## More - Full interactive human docs (Uzbek / Russian / English): https://istars.uz/api-docs - Terms of service: https://istars.uz/terms - Register: https://istars.uz/register · Login: https://istars.uz/login