You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Google Script修改Stripe支付链接:添加描述及生成定期链接

解决Stripe支付链接的两个需求:添加描述与转为定期支付

一、添加支付链接的描述选项

要给支付链接添加产品描述,需要在Stripe的Product对象中存入描述信息,同时在创建支付会话/链接时传递该字段。以下是具体修改步骤:

  1. 更新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;
}
  1. 修改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;
}
  1. 调整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;
}
  1. 修改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对象中设置重复计费规则:

  1. 在getPriceId中添加订阅规则:创建Price时传入recurring[interval]字段,指定订阅间隔(如month、year),同时更新缓存key和查询条件。
  2. 修改createSession的模式:将mode从payment改为subscription,确保会话使用订阅流程。
  3. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 02:54:22