Telegram Stars API — MyStars Fulfilment API documentation

Changelog

Every change to the public API, newest first.

  1. v1.12.0feature

    Payment window extended to 2 hours

    An order now stays open for payment for 2 hours instead of 1. Nothing changed in the shape of any request or response: expires_at on the order is still the single source of truth for the deadline, it simply lands further out. If you read expires_at rather than assuming a duration, your integration needs no change — and the spec no longer quotes a duration anywhere, precisely so it cannot go stale again. One thing worth re-checking: the SDK helpers that wait for an order to settle default to a 30-minute budget, which is now a quarter of the window rather than half, so raise it if you rely on the default to cover a full payment window.

  2. v1.11.0feature

    Recipient checks now tell you when they could not decide

    POST /v1/recipients/check always returns an `indeterminate` boolean. It is `true` when the probe could not reach a verdict and the endpoint failed open — meaning `eligible: true` is a permissive default, not a measurement — and `false` on every real verdict. Previously the two were indistinguishable on the wire, so a degraded probe looked exactly like a confirmed-deliverable recipient. Treat indeterminate as "unknown", never as "yes": proceeding to POST /v1/orders is safe (it runs its own authoritative check), but do not show the buyer a confirmed recipient. Strictly additive — the field was previously absent, and absent means the same as `false`.

  3. v1.10.0feature

    Batch pricing + a dedicated order-lifecycle rate-limit bucket

    New GET /v1/pricing/batch quotes up to 200 Stars quantities in ONE request (deduped, sorted; per-entry amount + fee match GET /v1/pricing cent-for-cent) — built for storefronts refreshing a whole pack catalog. Also: POST /v1/orders, GET /v1/orders/{id} and POST /v1/orders/{id}/cancel are now metered by a dedicated per-minute bucket of the same size as your general budget, isolated from read traffic — a burst of pricing or catalog reads can no longer 429 an order create, status poll, or cancel (and vice versa). Both changes are strictly additive; keep reading the RateLimit-* headers.

  4. v1.9.0feature

    Payment window extended to 1 hour

    An order now stays open for payment for 1 hour instead of 15 minutes. The order's expires_at field is unchanged in shape and remains the single source of truth for the deadline — it simply lands further out, giving payers more time. No request or response field changed; if you read expires_at (rather than assuming 15 minutes) nothing in your integration needs to change.

  5. v1.8.2feature

    Order create response echoes what was ordered

    POST /v1/orders now returns type plus quantity (for Stars) or months (for Premium) — the field that doesn't apply is null — so the created order is self-describing, just like GET /v1/pricing and the order view. You no longer have to correlate the response back to your request. Purely additive; existing fields are unchanged.

  6. v1.8.1fix

    Clearer docs: request-flow diagram + recipient-check guidance

    The reference now leads with the recommended call order (pricing → recipient check → order create) and a request-flow diagram in Quick start. POST /v1/recipients/check explains why type is required and warns that a recipient who already has an active Premium subscription can't be gifted Premium — Telegram blocks it (eligible:false, reason already_subscribed; the order would 422). Docs only — no contract change.

  7. v1.8.0feature

    USDT payments show a processing-fee breakdown

    For usdt_ton, GET /v1/pricing and the order-create payment block now include a fee object — subtotal, processing_fee (the 1% swap + 0.5 GRAM gas), total and a description — so you can see exactly what the swap costs. The fee was ALWAYS included in amount; this only itemises it (fee.total equals amount, never adds to it). GRAM quotes return fee: null. Purely additive.

  8. v1.7.1feature

    Pricing response echoes what it priced

    GET /v1/pricing now returns type plus quantity (for Stars) or months (for Premium) — the field that doesn't apply is null — so the amount is self-describing and you no longer have to correlate the quote back to your request. Purely additive; existing fields are unchanged.

  9. v1.7.0feature

    New: list available products

    A new GET /v1/products endpoint returns the product catalog — the two product types (stars, premium) and the buyable shape of each (stars: a continuous quantity range 50–1000000; premium: the fixed tiers 3/6/12 months). It's price-free metadata so you can build your own catalog/UI without guessing the bounds; keep using GET /v1/pricing for the price.

  10. v1.6.1fix

    Reversal terminology standardised

    The docs now use 'reversal' consistently to match the reversed order status and the reversal_tx field — the section is now 'Reversals & delivery' and adds a 'When a reversal happens' breakdown of the exact cases. No behaviour change: when and how your funds are returned is unchanged.

  11. v1.6.0feature

    Unmatched payments are auto-refunded

    A payment that arrives with no order reference (a missing or unrecognised memo) is now returned to the sender minus the network fee. If it can be attributed unambiguously to one of your pending orders, that order ends failed with failure_reason no_memo / wrong_memo and the refund reference in reversal_tx.

  12. v1.5.0feature

    Rate limits documented; probe cap raised to 30/min

    The overview now documents the per-minute request budget, the RateLimit-* / Retry-After headers, the daily order cap and the per-recipient guard. The tighter pricing & recipient-check probe cap was raised from 10 to 30 requests/min.

  13. v1.4.0feature

    Pricing response adds quote freshness + GRAM↔USDT rate

    GET /v1/pricing now returns quoted_at and valid_until (a re-quote hint) plus usdt_per_ton (the current public GRAM↔USDT rate; the field name is frozen for wire compatibility).

  14. v1.3.0feature

    Terminal failed and expired order-status webhooks now fire

    If you set a callback_url, you now also receive the terminal failed and expired webhook events — previously only delivered and reversed were delivered.

  15. v1.2.0breaking

    Pricing response returns amount + currency only

    GET /v1/pricing now returns just the final amount and currency. The previous breakdown object has been removed — amount is already the full, all-in total to pay, so no change is needed unless you read breakdown fields.

  16. v1.1.0feature

    Pay in USDT (TON), plus a price breakdown

    Orders and quotes now accept payment_currency: usdt_ton alongside ton (GRAM). The pricing response gained a breakdown object (Fragment cost, markup, gas, and DEX fee + swap gas for USDT).

  17. v1.0.0breaking

    recipient is now an object, not a bare string

    Create-order and recipient-check requests take recipient: { username } instead of a top-level username string. Update your request bodies before this version — the old shape is rejected with 400 bad_request.