前言
4个月了,朕又出现了!刁民没能害得了武功高强的朕
Stripe是一个用于全球收钱的在线服务,支持很多种货币,哪怕你人在美国,收人民币也行,Stripe会自动帮你转成账户对应的货币。Stripe支持的支付方式包括银行卡,Apple Pay,Google Pay甚至是国内非常流行的支付宝和微信。
当你有了Stripe账户之后,无代码的情况下可以弄一个收款链接或者二维码,用户通过他们的本地支付方式就可以给你塞钱了。比如说下图这里,用户就可以用支付宝来给我打钱。
集成Stripe
无代码的方式显然是不够的。很多情况下我们出售服务,或者说是软件授权,都需要自动化进行的。此时我们就可以利用Stripe的API了。想要利用这个API,主要就是两步:
- 创建
PaymentIntent
,主要就是定义了支持什么支付方式,想要收多少钱,想要什么币种 - 用户付款之后处理回调,比如说给用户发KEY啦之类的
我们以做一个用户任意捐款的页面为例(当然这个可以用Stripe的无代码,只是以此来作为例子),页面大概是这样子的
创建PaymentIntent
很丑有没有。用户输入一个金额,提交表单之后,后端需要请求创建Payment Indent,大概是这样的:
import stripe stripe.api_key =xxx @app.route('/checkout', methods=['POST']) def checkout(): method = request.form['method'] # unit is 分 amount = int(float(request.form['amount']) * 100) # create payment intent logging.info("method: %s, amount: %s", method, amount) intent = stripe.PaymentIntent.create(payment_method_types=[method], amount=amount, currency="cny") secret = intent.client_secret return render_template('checkout.html', pk=pk, secret=secret, method=method)
有几点需要注意的:
- method是付款方式,具体会受到国家地区和货币的限制
- amount是收多少钱,也就是用户在输入框里输入的,需要注意是会变成最小货币单位。对于人民币来说,最小的货币单位是分,也就是说收人民币12.34元,这个amount应该是1234;对于日元这种最小单位就是元的货币(零位十进制货币),收500日元那么就写500即可。
- pk是Stripe的API的public key,其实是可以公开的。写在前端的代码里是没问题的
- client_secret 对于每一个付款请求都是唯一的
发起请求
前端可以这么写,很简单,总之就是要让用户进入付款页面
const stripe = Stripe(pk); error = stripe.confirmAlipayPayment(clientSecret, { // Return URL where the customer should be redirected after the authorization return_url: `${window.location.origin}/callback`, });
测试模式下,用户会进入这样的页面
真实模式下是这样的
处理回调
用户付款,成功或者失败之后,会返回return url,我们通过URL就可以知道付款是否成功,当然通过API或者webhook也是可以的。
此时在Stripe的网页上就应该可以看到付款成功了
基本上简单来说就是这样的😂微信也差不多,只不过微信模式下stripe.js
会直接嵌入一个微信的二维码,然后需要用webhook或者API去验证用户是否已经付款,不能依赖callback url啦。完整代码可以看最后gist
Stripe 费率
在上面的那个Stripe的页面,能发现Stripe抽了不少钱,具体费率每个国家、每种支付方式都不一样。比如如果是加拿大,用支付宝支付,那么费率是2.9% + C$0.30,如果需要货币转换,有些国家也还要收钱的。具体信息可以看这里 https://stripe.com/zh-cn-ca/pricing/local-payment-methods,把ca(加拿大)替换成你的国家代码就有啦。
Telegram Bot Payment
Telegram很早之前也给bot提供了骗钱的功能,支持的收款服务商包括Stripe之类的。想要用Payment API,先要去和Bot Father申请,选择 Bot Settings-Payments,然后选择对应的付款提供商,比如Stripe,之后会被重定向到对应的bot,然后选择测试还是生产模式,做一下oauth就可以拿到一个token了
测试付款的时候可以用stripe的测试模式,有很多卡号可以模拟各种情况,成功失败都有,比如4242 4242 4242 4242就是可以用的测试卡,完整列表可以看这里。
一些Bot API wrapper,比如pytelegrambotapi已经有了很简单易懂的例子。这里我用的pyrogram(1.x)来做例子说明怎么生成、验证付款。
生成invoice
需要使用raw_types
from pyrogram.raw import types as raw_types raw_types.invoice.Invoice(currency="USD", prices=[raw_types.LabeledPrice(label="price", amount=amount)])
其中prices接受的参数是一个list,意味着这里可以有多项,比如说商品价格,税费,折扣,等等。amount同样遵循上面的最小货币单位原则,要收11.3美元,那么就要写1130
这里Invoice支持很多额外参数,比如email_requested
,name_requested
,suggested_tip_amounts
等等,自行发挥吧
生成InputMediaInvoice
raw_types.input_media_invoice.InputMediaInvoice( invoice=( raw_types.invoice.Invoice(currency="USD", prices=[raw_types.LabeledPrice(label="price", amount=amount)])), title=title, description=description, provider=PROVIDER_TOKEN, provider_data=raw_types.DataJSON(data="{}"), payload=payload, )
PROVIDER_TOKEN
是在Bot Father中申请的那个token,不是bot token。provider_data
是收款商需要要求的信息,比如印度Stripe强制要求姓名地址,那么就应该写在这里,否则Stripe会拒付。我这边没有要求,所以直接空json字符串就好- Payload是我们自定义的信息,内部使用,比如用于区分是什么的付款
如果要inline模式,那么就要用InputBotInlineMessageMediaInvoice
选择Forwarding Behavior
当invoice被转发了之后,我们可以选择有什么样的行为,一种是会可以继续付款,另外一种是通过deep linking跳转到机器人。由InputMediaInvoice
的参数start_param
控制的。直接忽略这个参数,意味着转发的消息也可以付款,并且付款后按钮不会变成receipt
发送invoice
用SendMedia
就可以了
peer = raw_types.InputPeerUser(user_id=chat_id, access_hash=0) app.send( functions.messages.SendMedia( peer=peer, media=inputinvoice, random_id=app.rnd_id(), message="pay for it!", ) )
Pre-Checkout
用户在付款之后,Telegram这边会给bot发一个pre_checkout_query
的更新,要求bot做一个precheckout的检查,比如说检查是否还有货啦这种。Bot需要在10秒之内用answerPreCheckoutQuery
应答,否则就会出错。
Pyrogram这边我没找到合适的事件监听,可能是版本太老了,所以只能这样了:
@app.on_raw_update() def raw_update(client: "Client", update, users, chats): if update.QUALNAME == 'types.UpdateBotPrecheckoutQuery': client.send( functions.messages.SetBotPrecheckoutResults( query_id=update.query_id, success=True ) )
- success表示pre checkout状态,如果是false,需要提供一个error
checkout
Bot确认之后,Telegram就会请求Stripe完成付款请求。之后telegram会发一个successful_payment
的service message,bot看到之后确认就可以了。
我们可以通过raw update的 types.MessageActionPaymentSentMe
来确认
打开你的Stripe,切换到测试模式,可以看到已经有“进账”啦,甚至还可以提现到银行卡😂
值得思考的问题
既然Stripe能支持支付宝微信付款,并且可以提现到银行卡,那么相比较银行汇款,哪个更划算呢?
已知条件如下:
- 招商银行通信费150元/笔,手续费为汇款金额的0.1%,最低100最高1000,不考虑境外银行的收费
- Stripe手续费 2.9%,无提现、货币转换费
- 均不考虑不同平台银行的汇率差异
欢迎大家给我打钱!
参考这里或者直接Stripe吧!
参考
https://core.telegram.org/bots/payments#step-by-step-process
https://stripe.com/docs/payments/alipay/accept-a-payment?locale=zh-CN
https://stripe.com/docs/payments/wechat-pay/accept-a-payment
https://stripe.com/zh-cn-ca/pricing/local-payment-methods
https://gist.github.com/BennyThink/d3a0de89d21ccb955636e0ffba0f9ea1