Перейти до основного вмісту
Інструкції

Повернення Telegram Stars: як насправді працює refundStarPayment

Також доступно мовами:ENRUUK
Опубліковано April 24, 20267 хв читання74 переглядів
Повернення Telegram Stars: як насправді працює refundStarPayment

Повернення Telegram Stars: як насправді працює refundStarPayment

Що отримаєте. Робочий обробник /paysupport, який дозволяє клієнту-платнику Stars запросити повернення прямо в чаті, аудитований виклик refundStarPayment за оригінальним telegram_payment_charge_id, обліковий запис на стороні оператора, що переживе ризик клавбеку від App Store/Google Play, і чітке правило для повернень за підпискою (яке ніколи не скасовує саму підписку — це окремий виклик editUserStarSubscription). Два аргументи API, одне дерево рішень і найчистіший support-флоу в екосистемі Stars.

Якщо платна Stars-поверхня вже працює, а обробки повернень немає — ви накопичуєте технічний борг. Планувальник Autogram передає refund-вебхук вашому боту так само, як передає платні дропи.

Що знадобиться

Кожен крок нижче спирається на такі передумови:

  • Бот, який уже прийняв принаймні один Stars-платіж. Без транзакції немає telegram_payment_charge_id, який можна повернути.
  • Постійний запис кожного successful_payment за ключем telegram_payment_charge_id → (user_id, tier_id, amount, paid_at). SQLite згодиться; in-memory — ні.
  • Обробник команди /paysupport. Stars ToS прямо каже користувачам надсилати /paysupport боту, коли вони хочуть повернення. Боти, що ігнорують команду, автоматично втрачають шлях ескалації.
  • Бібліотека на Bot API 7.4+ — refundStarPayment запустився разом із валютою Stars (червень 2024), тож усе, що підтримує XTR, підтримує і повернення.

Крок 1 — Вирішіть, чи повернення взагалі доречне

Photo by Yan Krukau on Pexels

Повернення доречне, коли виконано одну з умов нижче. Усе інше — кандидат на кредит, вибачення або запис у feature-request, але не повернення:

ТригерПовернення?Чому
Обіцяний контент не доставлено (404, биті лінки, відсутнє відео)Так, повнеРозділ 3.1 Stars ToS прямо покриває цей випадок
Користувач випадково купив двічі за коротке вікноТак, лише дублікатЖест доброї волі; дублікат не має бізнес-цінності
Підписка поновилась, а користувач не зрозумів, що це авторепейТак, лише останній періодПоверніть найсвіжіше списання; не чіпайте старі періоди
Контент доставлено, користувач передумавНіЗа ToS: «усі продажі Stars остаточні» після постачання цифрового товару
Користувач хоче часткове повернення з мульти-айтемного постуНі (неможливо)refundStarPayment не приймає суму — повернення лише повне
Списання старше за ~6 місяців (без офіційного ліміту, але практично)МожливоAPI не блокує, але Telegram міг уже обробити клавбек

Корисне правило: повернення робить клієнта цілим; кредит робить наступну покупку приємнішою. Коли сумніваєтесь — за замовчуванням кредит: він зберігає аудит-лог і LTV. Повернення — лише для «ми не доставили».

Крок 2 — Підключіть /paysupport, аби користувач міг попросити чисто

Коли користувач відкриває Налаштування → Telegram Stars → Транзакції і тапає по транзакції бота, UI Telegram показує кнопку «Зв'язатися з ботом для повернення», яка викликає /paysupport. Якщо бот не обробляє цю команду, користувач опиняється в мертвому чаті — і Telegram у своєму флоу ескалації позначить, що «розробник відмовився обробляти законне повернення». Така ескалація може закінчитися тим, що Telegram сам зніме Stars з вашого балансу пізніше. Обробляйте команду:

@router.message(Command("paysupport"))
async def on_paysupport(message: Message, db):
    user_id = message.from_user.id
    recent = await db.last_charges(user_id, limit=5)
    if not recent:
        return await message.answer(
            "У нас немає недавніх Stars-списань від вас. "
            "Відкрийте Налаштування → Telegram Stars → Транзакції, щоб побачити ID транзакції бота."
        )
    buttons = [
        [InlineKeyboardButton(
            text=f"Повернути {c.amount}⭐ від {c.paid_at:%Y-%m-%d}",
            callback_data=f"refund:{c.charge_id}",
        )] for c in recent
    ]
    await message.answer(
        "Оберіть списання, яке хочете повернути. "
        "Повернення відновлює повну оригінальну суму; часткові не підтримуються.",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons),
    )

Два нюанси, які треба засвоїти:

  • Завжди показуйте суму й дату перед дією. Stars-покупки зливаються між собою, і повернення «не того» списання породжує другий тікет.
  • Ніколи не повертайте автоматично без inline-підтвердження. Оператори, що ставлять «кожен /paysupport = миттєве повернення», за тиждень знаходять баланс бота на нулі — користувачі тестують флоу.

Крок 3 — Викликайте refundStarPayment

Photo by Towfiqu barbhuiya on Pexels

Два аргументи, один виклик Bot API, одна булева відповідь. Мінімальний обробник для inline-кнопки з кроку 2:

@router.callback_query(F.data.startswith("refund:"))
async def on_refund_confirm(query: CallbackQuery, bot: Bot, db):
    charge_id = query.data.removeprefix("refund:")
    charge = await db.get_charge(charge_id)
    if not charge or charge.user_id != query.from_user.id:
        return await query.answer("Списання не знайдено.", show_alert=True)
    if charge.refunded_at:
        return await query.answer("Уже повернено.", show_alert=True)
    try:
        await bot.refund_star_payment(
            user_id=charge.user_id,
            telegram_payment_charge_id=charge_id,
        )
    except TelegramBadRequest as e:
        # CHARGE_ALREADY_REFUNDED, USER_ID_INVALID, CHARGE_ID_EMPTY, USER_BOT_REQUIRED
        await db.log_refund_failure(charge_id, str(e))
        return await query.answer(f"Помилка повернення: {e.message}", show_alert=True)
    await db.mark_refunded(charge_id, refunded_by=query.from_user.id)
    await query.message.edit_text(
        f"Повернено {charge.amount}⭐ за {charge_id[:12]}…. "
        f"Stars уже у вашому гаманці."
    )

Поведінка, яку треба врахувати:

  • Миттєво й синхронно. Гаманець користувача поповнюється, баланс бота списується атомарно. Жодного «pending» стану немає.
  • Чотири задокументовані помилки: CHARGE_ALREADY_REFUNDED, CHARGE_ID_EMPTY, USER_BOT_REQUIRED, USER_ID_INVALID. Усе інше — транспорт або rate-limit; повторюйте з backoff.
  • Часткових повернень немає. Продали бандл на 1 000 Stars і користувач оскаржує 200? Повернення повне + новий рахунок за залишок. Плануйте розмір SKU відповідно.
  • Повернення підписочного списання не скасовує підписку. Наступне 30-денне поновлення все одно спрацює, якщо ви також не викличете editUserStarSubscription(is_canceled=True) за тим самим telegram_payment_charge_id. Спочатку повернення, потім скасування.

Крок 4 — Звірте повернення в обліку

Photo by Mikhail Nilov on Pexels

Боку бота — один виклик; бухгалтерії — три речі, які треба тримати у відповідності:

  1. Внутрішній лeджер. Позначте рядок refunded_at = now(), refunded_by = <admin user_id>. Не видаляйте оригінальне списання — повернення є дебетом проти існуючого кредиту.
  2. Баланс у Stars-дашборді. Повернення з'являються миттєво у Stars-out. Якщо ви виводите в TON за розкладом, повернення може опустити доступний баланс нижче 500-Star порога.
  3. Ризик клавбеку. Якщо користувач пізніше оскаржить покупку через App Store чи Google Play, Telegram залишає за собою право списати додаткові Stars з вашого балансу, щоб покрити те повернення. Тримайте запас на високовартісних списаннях.

Для будь-якого фінансового handoff'у, рядок, потрібний бухгалтеру: refund_id, original_charge_id, user_id, amount, original_paid_at, refunded_at, reason_code. Bot API не повертає refund_id — синтезуйте з (charge_id + refunded_at).

Поширені помилки

Чотири помилки, які перетворюють чисте повернення на спіраль тікетів:

  1. Викликати refund без збереження результату. Якщо ви викликали refundStarPayment, але не записали refunded_at, наступний /paysupport користувача знову покаже це списання як «доступне для повернення». Другий виклик поверне CHARGE_ALREADY_REFUNDED, і користувач побачить помилку.
  2. Повернути підписочне списання й забути про editUserStarSubscription. Користувач очікував «припиніть мене списувати»; ви видали «поверніть гроші за минулий місяць», але підписка лишилась активною. Наступне поновлення за 30 днів — другий, злий тікет.
  3. Авто-повернення з /paysupport без inline-підтвердження. Частина користувачів тапатимуть, аби перевірити, що буде. Inline-кнопка — це ваш контракт.
  4. Сприймати «немає вікна допустимості» як «повернення коли завгодно — безпечно». API не блокує старі списання, але Telegram міг уже звести оригінальний платіж із Apple/Google. Повернення такого списання може лишити баланс бота негативним.

Дотичні матеріали

Часті питання

Чи можна повернути лише частину Stars-платежу?

Ні. refundStarPayment приймає лише user_id і telegram_payment_charge_id — без поля суми, часткові повернення не підтримуються. Обхідні шляхи: повернути повністю та повторно виставити рахунок за залишок; або видати кредит у Stars-еквіваленті всередині бота.

Чи є часовий ліміт на повернення Telegram Stars?

Telegram не документує жорсткого вікна допустимості. Єдиний API-блокер — CHARGE_ALREADY_REFUNDED. Практично, повернення старші за ~3–6 місяців ризикові, бо Telegram міг уже звести оригінальну покупку з Apple/Google, і ви ризикуєте отримати клавбек-дебет пізніше.

Чи скасовує повернення підписочного списання саму підписку?

Ні. refundStarPayment повертає Stars лише за одне списання. Цикл поновлення триває. Щоб зупинити майбутні поновлення, додатково викличте editUserStarSubscription(user_id, telegram_payment_charge_id, is_canceled=True) за тим самим charge ID. Спочатку повернення, потім скасування.

Що відбувається зі Stars користувача після повернення?

Миттєво зараховуються назад на Stars-баланс користувача. Він може витратити їх на будь-яку іншу Stars-поверхню, вивести через Fragment там, де це підтримується, або — у випадку клавбеку через Apple/Google — побачити, як вони зникнуть, коли платформа обробить власне повернення.

Чи маю я обов'язково обробляти /paysupport?

Так, на практиці. UI Telegram направляє користувачів до /paysupport із Налаштувань → Stars. Бот, який її не обробляє, лишає користувача без in-chat шляху вирішення; той ескалює до Telegram, який може зняти Stars з вашого балансу для покриття повернення. Обробляйте навіть із простою «відповімо протягом 24 годин».

Чи може користувач оскаржити Stars-покупку через Apple або Google?

Так — Stars купуються через in-app purchase, тому повернення на рівні платформи можливі. Якщо користувач робить це після того, як ви вже постачили цифровий товар, Telegram може зняти еквівалент Stars з балансу бота для компенсації. Тримайте Stars-запас проти високовартісних списань.

Підсумок

Повернення — це виклик API з двома аргументами, обгорнутий у чотирикрокову операційну дисципліну: вирішити, що повернення доречне, дати користувачу чистий /paysupport флоу, викликати refundStarPayment із підтвердженням, звірити облік. Технічна поверхня крихітна; бізнес-поверхня — все, що навколо. Запустіть обробник /paysupport до наступного платного дропу — дивіденди довіри накопичуються, ризик клавбеку зменшується.

Тарифи в Autogram. Підключіть перший канал і отримайте 7 днів доступу до Solo з AI-бюджетом $1. Банківська картка не потрібна.

Авторство фото

#повернення telegram stars#refundstarpayment#paysupport#telegram bot повернення#stars chargeback#telegram subscription refund#refund stars api

Підпишіться на нашу розсилку

Отримуйте найновіші поради з розвитку Telegram, стратегії автоматизації та оновлення платформи на вашу пошту.

Або підпишіться на наш Telegram-канал