1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

KLab EngineerAdvent Calendar 2024

Day 5

Telegram Mini AppでStar課金を実装する方法

Last updated at Posted at 2024-12-05

Telegram Mini AppのStar課金について

Telegram Mini Appでは、Telegramのアプリ内通貨「Star」を使用してデジタルアイテムを販売できます。

この記事では、Star課金の実装方法について詳しく解説します。

事前準備

Starの購入

まず、Star課金で使用するStarを購入しましょう。Telegramのテスト環境と本番環境では購入方法が異なります。

テスト環境でStarを無料で入手する方法

Telegramのテスト環境では、テスト用のクレジットカードを使用する事でStarを無料で入手可能です。

テスト環境への切り替え方法

Telegramアプリでのテスト環境への切り替え方法はプラットフォームごとに異なります。一部のプラットフォーム(Android版、Web版など)ではテスト環境は利用できません。

  • Telegram iOSアプリ版

    設定アイコンを10回タップ → アカウント → 別のアカウントにログイン → テスト

  • Telegram デスクトップ版

    メニュー(☰) → [Settings] → [MyAccount] を開き、Shift + Alt + [アカウントの追加] を右クリック→ [テスト サーバー] を選択

  • Telegram macOS版

    設定アイコンを 10 回クリックしてデバッグ メニューを開き、⌘ キーを押しながら「アカウントの追加」をクリック → 電話番号でログイン


Starの購入方法

デスクトップ版またはmacOS版のTelegramアプリを使用してテスト環境に切り替え、設定画面の「My Stars」を開きます。クレジットカード情報を入力してStarを購入します。
詳しくは
クレジットカード番号はドキュメントに記載されている番号を入力して、カード番号以外の情報は任意で構いません。

カード情報の入力
スクリーンショット 2024-11-23 3.38.42.png

(注意)iOS版TelegramではクレジットカードでのStar購入ができないため、無料での取得方法はありません


テスト環境でMini Appを作成する

テスト環境で購入したStarは、テスト環境で作成したMini Appでのみ利用できます。
以下のリンクからテスト環境のBotFatherにアクセスし、Mini Appを作成してください。

テスト環境のAPIエンドポイントについて

テスト環境では、Telegram APIのエンドポイントが以下のように変わります。

  • 本番環境のAPIエンドポイント
    https://api.telegram.org/bot<token>/METHOD_NAME
  • テスト環境のAPIエンドポイント
    https://api.telegram.org/bot<token>/test/METHOD_NAME

例えば、pyTelegramBotAPIを使用する場合、以下のようにエンドポイントを変更します。

from telebot import apihelper
apihelper.API_URL = "https://api.telegram.org/bot{0}/test/{1}"

本番環境でStarを購入する方法

本番環境では、iOS/Android版のTelegramアプリからStarを購入できます。ただし、プラットフォーム手数料が上乗せされるため、割高になります。

Fragmentという外部サイトでは、Starを\$TON(Toncoin)で販売しており、より安価に購入可能です。

FragmentではStarのほか、Telegram Premium、ユーザー名、電話番号なども\$TONで販売しています。

\$TONとは?
TONは、Telegramが開発を始めたブロックチェーンで、プロジェクト開始当初は「Telegram Open Network」という名称で進められていましたが、現在は「The Open Network」と改称され、非営利団体であるTON Foundationによって開発・運営されています。
\$TON(Toncoin)は、TONのネイティブトークンです。
https://ton.org/

テスト環境、本番環境どちらで開発すべき?

テスト環境ではStarを無料で利用できるため初期コストを抑えられます。一方、本番環境での開発にはStarの購入費用がかかりますが、後述する返金処理でMiniAppに支払ったStarは回収可能です。どちらを選ぶかは、プロジェクトの要件に応じて判断してください。


Star課金の実装方法

Telegramからの課金イベント通知用Webhookの登録

Star課金では、Telegramサーバーからの課金イベント通知をWebhookで受け取る必要があります。そのため、まずWebhookの登録を行います。

以下は、FlaskとpyTelegramBotAPIを使ったサンプルコードです。

WebhookのURLの登録

WebhookのURLには、推測されにくいようにTOKENを含めることを推奨します。

# webhook urlを設定
webhook_url = f"https://your-domain.com/{telegram_token}/webhook"
bot.set_webhook(
  url=webhook_url,
  allowed_updates=['message', 'callback_query', 'pre_checkout_query'] # 受信するメッセージ
)

URLだけでは不安な場合は、シークレットトークンを設定することも可能です。シークレットトークンを設定すると、Webhookリクエストに「X-Telegram-Bot-Api-Secret-Token」ヘッダーが追加されます。

bot.set_webhook(
  url=webhook_url,
  allowed_updates=['message', 'callback_query', 'pre_checkout_query'],
  secret_token="XXXXXXXXXXXX" # シークレットトークンを設定
)

Webhookの受信処理

Webhookに設定したURLの受信処理を以下のように実装します。

@app.route(f"/{telegram_token}/webhook", methods=['POST'])
def webhook():
  update = telebot.types.Update.de_json(request.stream.read().decode("utf-8"))
  self.bot.process_new_updates([update])
  return "OK"

Star課金処理の流れ

①購入ボタン→請求画面表示

ユーザーが購入ボタンを押してから請求画面を表示するまでのフローを説明します。

1: ユーザーがアイテムの購入ボタンを押します。

2: ClientがServerAPIを呼び出して請求書URLを要求します。

3: Serverは、Telegram APIのcreate_invoice_link関数を使用して請求書URLを生成します。
create_invoice_link関数のパラメーターには販売するアイテム名や価格情報などを含めます。
payloadはユーザーには公開されないデータで、支払いプロセス中に参照できるデータなので、ここに販売するアイテム情報などを含めましょう。payloadは128バイトまでの容量制限があります。
発行した請求書URLをClientに渡します。

サンプルコード:請求書URLの生成

title = "ポーション"
description = "体力を10回復する"
provider_token = "" # Star支払いの場合は空文字
currency = "XTR"  # Star支払いの場合はXTR
amount = 100 # 販売価格
prices = [telebot.types.LabeledPrice(label=title, amount=amount)]

# payloadに販売情報を含める
payload = urllib.parse.urlencode({'item_id': 5})

# 請求書URLを発行
bot = telebot.TeleBot(telegram_token)
invoice_link = bot.create_invoice_link(
  title, description, payload, provider_token, currency, prices
)

# クライアントに請求書URLを渡す
return invoice_link

4: ClientはServerから受け取った請求書URLを使って請求画面を表示します。
twa-dev/sdkを使用している場合は、WebApp.openInvoiceメソッドを使用して、ユーザーに支払い確認画面を表示できます。

サンプルコード:請求画面の表示

WebApp.openInvoice(
  invoice_link,
	function (status) {
	  // 購入後のコールバック
      switch (status) {
	    case "paid":
	    case "failed":
	    case "cancelled":
	    case "pending":
	  }
  });
});

支払い確認画面

②ユーザーが請求書を確認して支払いを行う

請求書画面が表示された後、ユーザーが支払いを完了するまでのフローは以下の通りです。

1 ユーザーが請求書画面でStar支払いを行います。

2 Telegramが支払い直前イベント通知(PreCheckoutQuery)をAppServerに送信します。
このリクエストには購入者・請求情報・payloadなどの支払い内容が含まれます。
3 AppServer側で、受信した支払い内容を検証し、answerPreCheckoutQueryで支払いの承認もしくはキャンセルを行います。

サンプルコード:支払い直前イベント通知(PreCheckoutQuery)の受信処理

bot = telebot.TeleBot(telegram_token)

def pre_checkout_query_filter(query):
  payment_info = dict(urllib.parse.parse_qsl(query.invoice_payload))
  return True

@bot.pre_checkout_query_handler(func=pre_checkout_query_filter)
def handle_pre_checkout_query(query):
  if is_valid(query):
    # 支払い承認通知を送信
    bot.answer_pre_checkout_query(query.id, ok=True)
  else:
    # 支払いキャンセル通知を送信
    bot.answer_pre_checkout_query(query.id, ok=False, error_message="無効な商品情報です。")

4 支払いが完了するとTelegramが支払い完了イベント通知(SuccessfulPayment)をAppServerに送信します。

リクエストパラメーターには以下のような情報が含まれるので必要に応じてデータベースなどに保存します。
請求書URL発行時のpayloadには購入したアイテム情報が含めているので、購入者にアイテムの付与を行います。
telegram_payment_charge_idは返金処理で必要になるので必ず保存しておきましょう。

リクエストパラメーター

  • 購入者情報
  • 販売価格
  • telegram_payment_charge_id
  • 請求書URL発行時のpayload

サンプルコード:支払い完了イベント通知(successful_payment)の受信処理

@bot.message_handler(content_types=["successful_payment"])
def handle_successful_payment(message):
    user_id = message.from_user.id
    telegram_payment_charge_id = (
        message.successful_payment.telegram_payment_charge_id
    )
    amount = message.successful_payment.total_amount
    payment_info = dict(parse_qsl(message.successful_payment.invoice_payload))
    
    # telegram_payment_charge_idをDBに保存
    add_payment_info(user_id, telegram_payment_charge_id, amount)
    
    # 購入者にアイテムを付与
		add_item_to_user(user_id, payment_info.get("item_id"))

参考

返金処理の実装

アプリ側で返金処理を行う方法

  1. ユーザーから取引で発行されたTransactionIDを教えてもらいます。TransactionIDはTelegramの設定画面にあるスターの取引履歴から確認できます
  2. アイテム販売時の支払い完了イベント通知(SuccessfulPayment)で受け取ったtelegram_payment_charge_idと、1で取得したTransactionIDが一致するかを確認します
  3. 返金は、refundStarPayment関数を使用して行います。この関数に返金対象のuser_idと1で取得したTransactionIDをパラメータとして渡します
  4. 必要に応じて、返金後にデジタルアイテムの没収などを行います

返金完了イベント通知

Telegram Bot APIの仕様によると、refunded_paymentというメッセージがWebhookで届くようですが、どのような操作を行った場合にこの通知が発生するのか、ドキュメントでは見つかりませんでした。

もし詳細をご存知の方がいれば、ぜひ教えてください。

参考 

売上を受け取る方法

Starの売上は、Apple/Googleのプラットフォーム手数料(30%)およびTelegramの手数料を差し引いた額が、\$TONで受け取れます。現在、1スターあたり0.013米ドル相当の\$TONが支払われます。

受け取り方法は、Telegramアプリ(Web版以外)のMiniAppの詳細画面から「スター残高ページ」に遷移することで確認・操作が可能です。

ただし、1スター以上の売上がない場合、この「スター残高ページ」に遷移するためのボタンは表示されませんのでご注意ください。

参考

サポート窓口

Telegram Mini Appでは、ユーザーからの支払いに関する問い合わせを受け付けるため、チャットコマンド /paysupport を実装する必要があります。

サンプルコード:/paysupportの処理

@bot.message_handler(commands=["paysupport"])
def handle_paysupport(message):
    bot.send_message(
        message.chat.id,
        """
お支払いに関するお問い合わせは、以下のフォームよりご連絡ください。
http://example.com/paysupport/form
""".strip(),
    )

参考

その他の注意事項

Star課金はTelegram側の審査を必要としませんが、Apple/Googleのアプリ内購入(IAP)のガイドラインに従う必要があります。

支払いに関するガイドラインの詳細については、以下のリンクをご参照ください:
Telegram Bot Developers - Payments

開発中にハマった事

当初vercel(Hobby Plan)を使って開発していましたが、Webhookの通知が届かない問題に悩まされていました。
おそらくvercelが共有サーバーのため?なのか、他のvercelユーザーの影響でTelegram側からアクセス制限がかかっている可能性が考えられます。
同様の問題が起こった場合は、aws等でインスタンスを用意する事をおすすめします。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?