在 Telegram Mini App 中使用 grammY 进行 Telegram Stars 支付的流程

2,094 阅读3分钟

为了应对 Apple 和 Google 关于数字产品销售的政策监管需要, Telegram 上线了 Telegram Stars 作为支付方式。Telegram Stars 是一种新的应用内货币,用于购买数字商品和服务。用户可以使用 Apple Pay 或 Google Pay 直接在 Telegram 中购买 Stars。

本文以 nodejs 的机器框架 grammY 以及 expressjs 为例介绍使用 Telegram Stars 在 Telegram Mini App 中支付的流程。

创建机器人

这里假设你已经通过 BotFather 创建好你的机器人。
首先安装 grammY 依赖包

pnpm add grammy
pnpm add express

新建 bot.js 并初始化机器人

const express = require('express')
const { Bot } = require('grammy')
const BOT_TOKEN = '你的机器人token'
const bot = new Bot(BOT_TOKEN)
const app = express()

bot.command('start', ctx => ctx.reply('欢迎,打钱吧。'))
bot.start()

app.listen(3000, () => {
  console.log(`Server is running on http://localhost:${port}`)
})

第一步:创建账单

有两种创建账单的方法:

  1. sendInvoice: 机器人向用户发送一条带有支付界面的消息,允许他们在聊天中完成交易。它包括标题、描述、货币、价格等详细信息,以及照片和有效载荷等其他可选参数。
  2. createInvoiceLink: 此命令生成账单链接。当用户点击该链接时,他们会被重定向到支付界面以完成交易。此方法适用于在 Telegram 聊天之外共享支付链接,例如在 Telegram Mini Apps、电子邮件或网站上。

服务端

因为我是在 Telegram Mini App 中使用,所以这里用 createInvoiceLink 方法。
首先用 express 创建一个接收付款请求的路由:

app.post('/api/generate-invoice', async (req, res) => {
  const title = '测试商品'
  const description = '商品描述'
  const payload = '{}'
  const currency = 'XTR' // XTR代表 Telegram Stars
  const prices = [{ amount: 1, label: '测试商品' }]

  const invoiceLink = await bot.api.createInvoiceLink(
    title,
    description,
    payload,
    '', // 这个参数是 Provider token , 但是虚拟商品是不需要的,留空即可
    currency,
    prices
  )

  res.json({ invoiceLink })
})

小程序端

在小程序端,使用 @twa-dev/sdk 库处理支付。
首先安装 @twa-dev/sdk 依赖

pnpm add @twa-dev/sdk

给支付按钮绑定点击事件,获取到 invoiceLink, 再使用 openInvoice 方法打开支付弹窗

import WebApp from '@twa-dev/sdk'

document.querySelector('.pay-button').addEventListener('click', () => {
  fetch('/api/generate-invoice')
    .then(res => res.json())
    .then(({ invoiceLink }) => {
      WebApp.openInvoice(invoiceLink, status => {
        // status 有四种状态: paid | cancelled | failed | pending
        if (status === 'paid') {
          // 支付成功后的处理
        }
      })
    })
})

Snipaste_2024-09-19_18-48-29.png

第二步:处理 pre_checkout_query

接下来必须处理支付请求。当用户点击付款按钮时,Telegram 的机器人 API 会向你的机器人发出一个包含订单信息的字段pre_checkout_query, 机器人必须在 10 秒内用 answerPreCheckoutQuery 方法做出回应,否则交易将被取消。 如果机器人不能处理这个订单,则必须向用户解释原因,Telegram 会把这个信息展示给用户。比如:您购买的商品库存不足。

bot.on('pre_checkout_query', ctx => {
  // 如果不检查直接通过的话: ctx.answerPreCheckoutQuery(true)
  return ctx.answerPreCheckoutQuery(false, '商品库存不足').catch(() => {
    console.error('answerPreCheckoutQuery failed')
  })
})

第三步:处理支付成功事件

在机器人服务端, 添加对事件successful_payment的监听。 此时,用户已经完成支付,他的 Star 已经打到你的账户了。

bot.on('message:successful_payment', async (ctx) => {
  if (!ctx.message || !ctx.message.successful_payment || !ctx.from) {
    return
  }

  // 写入数据库, 这里用 mongoDB
  // 必须把 telegram_payment_charge_id 存起来,如果用户需要退款的话
  const collection = db.collection('payments')
  await collection.insertOne({
    user: ctx.from.id,
    charge_id: ctx.message.successful_payment.telegram_payment_charge_id
  })
})

好了,这就是一个完整的支付流程了。