基于Google Script修改Stripe支付链接:添加描述及生成定期链接
解决Stripe支付链接的两个需求:添加描述与转为定期支付
一、添加支付链接的描述选项
要给支付链接添加产品描述,需要在Stripe的Product对象中存入描述信息,同时在创建支付会话/链接时传递该字段。以下是具体修改步骤:
- 更新
getProductId方法:新增description参数,创建Product时传入描述,同时更新缓存key(避免同名不同描述的产品冲突):
getProductId(name, description = '') { const cacheKey = `${name}-${description}`; const productId = this.getCache(cacheKey); if (productId) return productId; const api = 'https://api.stripe.com/v1/products'; const { data = [] } = this.getData(api, { limit: 100 }); const { id: newProductId } = data.find(({ name: productName, description: prodDesc }) => productName === name && prodDesc === description) || this.postData(api, { name, description }); this.setCache(cacheKey, newProductId); return newProductId; }
- 修改
getPriceId方法:新增description参数并传递给getProductId,同时更新缓存key:
getPriceId(name, price = '1234', currency = 'USD', description = '', interval = 'month') { const product_id = this.getProductId(name, description); const key = `${product_id}-${price}-${currency}-${description}-${interval}`; const priceId = this.getCache(key); if (priceId) return priceId; const api = 'https://api.stripe.com/v1/prices'; const { data = [] } = this.getData(api, { limit: 100, currency, product: product_id }); const { id: newPriceId } = data.find(({ unit_amount, recurring }) => String(unit_amount) === String(price) && recurring?.interval === interval) || this.postData(api, { currency, product: product_id, unit_amount: price, 'recurring[interval]': interval }); this.setCache(key, newPriceId); return newPriceId; }
- 调整
createLink方法:新增description和interval参数,更新缓存key并传递给getPriceId:
createLink(name, amount, currency, description = '', interval = 'month') { const key = `link-${amount}-${currency}-${name}-${description}-${interval}`; const paymentLink = this.getCache(key); if (paymentLink) return paymentLink; const priceId = this.getPriceId(name, Math.ceil(amount * 100), currency, description, interval); const { url } = this.postData('https://api.stripe.com/v1/payment_links', { 'line_items[0][price]': priceId, 'line_items[0][quantity]': 1, }); this.setCache(key, url); return url; }
- 修改
createSession方法:新增description和interval参数,在product_data中加入描述字段:
createSession(name, amount, currency, description = '', interval = 'month') { const STRIPE_SUCCESS_URL = 'youtube.com'; const STRIPE_CANCEL_URL = 'bing.fr'; const key = `session-${amount}-${currency}-${name}-${description}-${interval}`; const sessionLink = this.getCache(key); if (sessionLink) return sessionLink; const { url } = this.postData('https://api.stripe.com/v1/checkout/sessions', { cancel_url: STRIPE_CANCEL_URL, success_url: STRIPE_SUCCESS_URL, mode: 'subscription', billing_address_collection: 'required', 'payment_method_types[]': 'card', 'line_items[0][price_data][currency]': currency, 'line_items[0][price_data][product_data][name]': name, 'line_items[0][price_data][product_data][description]': description, 'line_items[0][price_data][unit_amount]': Math.ceil(amount * 100), 'line_items[0][price_data][recurring][interval]': interval, 'line_items[0][quantity]': 1, }); this.setCache(key, url); return url; }
二、将一次性支付改为定期支付(订阅模式)
Stripe的定期支付需要切换为订阅模式(subscription),并在Price对象中设置重复计费规则:
- 在
getPriceId中添加订阅规则:创建Price时传入recurring[interval]字段,指定订阅间隔(如month、year),同时更新缓存key和查询条件。 - 修改
createSession的模式:将mode从payment改为subscription,确保会话使用订阅流程。 - 在
createLink中传递订阅参数:确保支付链接使用带有订阅规则的Price。
完整修改后的代码
/** * * Author : Amit Agarwal * Email : amit@labnol.org * Website : https://digitalinspiration.com/ * License. : MIT Attribution required * * */ const StripeAPI = { getCache(key) { return CacheService.getScriptCache().get(key); }, setCache(key, value) { CacheService.getScriptCache().put(key, value, 21600); }, convertPayload(params = {}) { return Object.entries(params) .map(([key, value]) => [encodeURIComponent(key), encodeURIComponent(value)].join('=')) .join('&'); }, getData(endpoint, params) { const response = UrlFetchApp.fetch(`${endpoint}?${this.convertPayload(params)}`, { headers: { Authorization: `Bearer ${STRIPE_API_KEY}`, }, muteHttpExceptions: true, }); return JSON.parse(response); }, postData(endpoint, params) { const response = UrlFetchApp.fetch(endpoint, { method: 'POST', headers: { Authorization: `Bearer ${STRIPE_API_KEY}`, 'Content-Type': 'application/x-www-form-urlencoded', }, muteHttpExceptions: true, payload: this.convertPayload(params), }); return JSON.parse(response); }, getProductId(name, description = '') { const cacheKey = `${name}-${description}`; const productId = this.getCache(cacheKey); if (productId) return productId; const api = 'https://api.stripe.com/v1/products'; const { data = [] } = this.getData(api, { limit: 100 }); const { id: newProductId } = data.find(({ name: productName, description: prodDesc }) => productName === name && prodDesc === description) || this.postData(api, { name, description }); this.setCache(cacheKey, newProductId); return newProductId; }, getPriceId(name, price = '1234', currency = 'USD', description = '', interval = 'month') { const product_id = this.getProductId(name, description); const key = `${product_id}-${price}-${currency}-${description}-${interval}`; const priceId = this.getCache(key); if (priceId) return priceId; const api = 'https://api.stripe.com/v1/prices'; const { data = [] } = this.getData(api, { limit: 100, currency, product: product_id }); const { id: newPriceId } = data.find(({ unit_amount, recurring }) => String(unit_amount) === String(price) && recurring?.interval === interval) || this.postData(api, { currency, product: product_id, unit_amount: price, 'recurring[interval]': interval }); this.setCache(key, newPriceId); return newPriceId; }, createLink(name, amount, currency, description = '', interval = 'month') { const key = `link-${amount}-${currency}-${name}-${description}-${interval}`; const paymentLink = this.getCache(key); if (paymentLink) return paymentLink; const priceId = this.getPriceId(name, Math.ceil(amount * 100), currency, description, interval); const { url } = this.postData('https://api.stripe.com/v1/payment_links', { 'line_items[0][price]': priceId, 'line_items[0][quantity]': 1, }); this.setCache(key, url); return url; }, createSession(name, amount, currency, description = '', interval = 'month') { const STRIPE_SUCCESS_URL = 'youtube.com'; const STRIPE_CANCEL_URL = 'bing.fr'; const key = `session-${amount}-${currency}-${name}-${description}-${interval}`; const sessionLink = this.getCache(key); if (sessionLink) return sessionLink; const { url } = this.postData('https://api.stripe.com/v1/checkout/sessions', { cancel_url: STRIPE_CANCEL_URL, success_url: STRIPE_SUCCESS_URL, mode: 'subscription', billing_address_collection: 'required', 'payment_method_types[]': 'card', 'line_items[0][price_data][currency]': currency, 'line_items[0][price_data][product_data][name]': name, 'line_items[0][price_data][product_data][description]': description, 'line_items[0][price_data][unit_amount]': Math.ceil(amount * 100), 'line_items[0][price_data][recurring][interval]': interval, 'line_items[0][quantity]': 1, }); this.setCache(key, url); return url; }, };
使用示例
调用生成订阅链接时可传入描述和订阅间隔:
// 生成每月9.99美元的会员订阅链接,带描述 StripeAPI.createLink("月度会员", 9.99, "USD", "每月自动续费,享受专属内容与服务", "month")
内容的提问来源于stack exchange,提问作者Ludo Figueiredo
相关产品推荐
相关产品推荐

