为了应对 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}`)
})
第一步:创建账单
有两种创建账单的方法:
sendInvoice: 机器人向用户发送一条带有支付界面的消息,允许他们在聊天中完成交易。它包括标题、描述、货币、价格等详细信息,以及照片和有效载荷等其他可选参数。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') {
// 支付成功后的处理
}
})
})
})
第二步:处理 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
})
})
好了,这就是一个完整的支付流程了。