DEV Community

Cover image for Telegram gift auctions in the MTProto API: rounds, bid position and refunds
StarGate
StarGate

Posted on Fully Autonomous

Telegram gift auctions in the MTProto API: rounds, bid position and refunds

Since November 2025, new limited Telegram gifts are released through auctions instead of a fixed-price sale. Bids are paid in Stars, carry over between rounds and are refunded when the auction ends. If you build a client, a gift tracker or a bot that deals with Stars, this changes what you show users and when their Stars come back. This post walks through the auction docs and the related client configuration values.

Spotting an auction gift

An auctioned gift is a starGift with the auction flag set, plus auction_slug, gifts_per_round and auction_start_date. The docs are strict about it: such a gift "is auction-only: it must not be bought through the normal gift sending flow". The slug builds a t.me/auction/<slug> deep link.

Reading the state

  • payments.getStarGiftAuctionState(auction, version) returns the gift, the auction state and the current user's state, and subscribes the client to updateStarGiftAuctionState for timeout seconds. Call it again after timeout to keep receiving updates.
  • payments.getStarGiftActiveAuctions(hash) returns every unfinished auction the user has bid on, including ones where the bid was returned. Clients use it at startup to show an auction badge.
  • Apply a starGiftAuctionState only if its version is bigger than the cached one: the server "may sometimes return slightly outdated cached versions". A starGiftAuctionStateFinished has no version and replaces any cached state.

Rounds

The auction has total_rounds rounds. Each round gives gifts_per_round gifts to the top bidders of that round, so the total supply is gifts_per_round * total_rounds. rounds describes them compactly: each StarGiftAuctionRound covers rounds from its num up to the next entry's num - 1. An extendable round (starGiftAuctionRoundExtendable) has extend_top and extend_window: a change in the top extend_top positions prolongs the round by extend_window seconds, so a late bid near the top extends the round instead of closing it.

gifts_left is the live count of gifts still to distribute. It overrides starGift.availability_remains, which lags behind because updates do not refresh it.

Bids

A bid is a normal Stars payment: payments.getPaymentForm with inputInvoiceStarGiftAuctionBid (peer, gift_id, bid_amount, optional message and hide_name; update_bid to raise an existing bid). Things that matter for UX:

  • A bid "cannot be retracted". The only outcomes are a win, a higher bid, or a refund when the user loses everything and the auction finishes.
  • A bid outside the top N of a round carries over to the next round automatically.
  • starGiftAuctionUserState.min_bid_amount, when present, overrides the auction-wide min_bid_amount for this user.
  • returned means the bid fell so far behind that it can never win, even if nobody bids again. It was removed and refunded; to take part again the user has to place a new bid.
  • Bids appear in the Stars transaction history with the stargift_auction_bid flag.

Estimating the user's position

bid_levels holds exact positions for the first 100 places and coarser checkpoints after that (100, 200 … 1,000, 2,000 … gifts_left). Equal amounts rank by time: the earlier bid is higher. The documented algorithm, as code:

def auction_position(state, user_state, my_id):
    if my_id in state.top_bidders:
        return state.top_bidders.index(my_id) + 1
    for level in state.bid_levels:  # ascending by position
        if (level.amount == user_state.bid_amount and level.date >= user_state.bid_date) \
                or level.amount < user_state.bid_amount:
            return level.pos
    return state.bid_levels[-1].pos + 1

def expected_gift_number(state, position):
    return state.last_gift_num + position
Enter fullscreen mode Exit fullscreen mode

Positions from coarse checkpoints are approximate, so round the displayed number accordingly.

Winning, and what you cannot do afterwards

Won gifts arrive as messageActionStarGift with auction_acquired set; gift_num is the collectible number. payments.getStarGiftAuctionAcquiredGifts lists everything the user won, with bid amount, round and position.

Two limits to surface in the UI:

  • "Gifts acquired through collectible gift auction cannot be converted back into Telegram Stars."
  • After the auction, starGiftAuctionStateFinished gives average_price, and optionally listed_count (on resale in Telegram, fetch with payments.getResaleStarGifts) and fragment_listed_count with fragment_listed_url.

Resale economics from the client config

If a user resells the gift, the seller receives price * permille / 1000. The documented config example has:

Key Value Meaning
stars_stargift_resale_commission_permille 800 seller gets 80% of a price in Stars
ton_stargift_resale_commission_permille 900 seller gets 90% of a price in GRAM (nanograms)
stars_stargift_resale_amount_min 125 minimum resale price in Stars
stars_stargift_resale_amount_max 100000 maximum resale price in Stars

Read these from help.getAppConfig at runtime instead of hardcoding them: they are configuration, not protocol constants.

What this means for Stars flows

Auctions move Stars in bursts. Users top up before a release, Stars stay locked while bids are in play, and losing bids land back on balances in one wave when the auction ends. Resales paid in Stars add more. If your bot accepts Stars, expect payment spikes after big auctions, and remember that Stars paid to a bot follow the usual availability rules in the Bot Platform Developer Terms.

Checklist

  • [ ] treat starGift.auction gifts as bid-only, never send them through the normal gift flow
  • [ ] apply auction states by version; apply starGiftAuctionStateFinished unconditionally
  • [ ] show the bid as locked until a win, a refund or returned
  • [ ] estimate position from bid_levels and label approximate positions
  • [ ] tell users that auction gifts cannot be converted back into Stars
  • [ ] read resale commission and limits from the app config

Disclosure: we build StarGate, a Telegram bot and web app that swaps Stars for GRAM, USDT, ETH and BTC. This post was drafted by an AI assistant from the Telegram documentation linked above, and every quote was checked against those pages.

Top comments (0)