Learn how to Integrate Stripe Payments API Using Google Apps Script.

The Stripe Payment Links Generator creates one-time payment links that can be shared with customers. It was originally developed by Amit Argarwal, whom I credit for this work. His version of the automation consists of using Google Apps Script to call the Stripe Payments API to generate a payment link for a single item. He also implements a cache system to enhance performance.

Expanding on his script, I introduced 3 new features:

  1. Multiple Item Payment Links: Users can specify up to 20 items they wish to sell, allowing them to include several items in one payment link.
  2. Post-Payment Actions: Following a successful payment, users can opt to redirect customers to a designated URL or display a custom message.
  3. Receipt and Post-Purchase Invoice: Stripe automatically sends a receipt and post-purchase invoice to the customer’s email upon completing a payment.

Please ensure proper configuration of the Stripe API when using this script.

/**
 * How to Integrate Stripe Payments API Using Google Apps Script
 * 
 * Written with ❤️ by Joseph Asinyo
 */



// Insert the API key you created on your Stripe dashboard
const STRIPE_API_KEY = "INSERT STRIPE API KEY HERE TO START";


/**
 * Generate a Stripe payment link for multiple items using Google Sheets
 *
 * @param {Array} items An array of arrays, where each sub-array contains the item name and the amount to be charged
 * @param {string} currency The 3-letter currency code for the items
 * @param {string} actionAfterPayment This is either an https URL to redirect the buyer to after payment or a text message to display after payment 
 * @return {string} Stripe payment link
 * @customfunction
 */

function STRIPE(items, currency, actionAfterPayment) {
  return createLink(items, currency, actionAfterPayment);
}


function createLink(items, currency, actionAfterPayment) {
  const lineItems = items.map((item, index) => {
    const priceId = getPriceId(item[0], Math.ceil(item[1] * 100), currency);
    return {
      [`line_items[${index}][price]`]: priceId,
      [`line_items[${index}][quantity]`]: 1
    };
  });

  var key = `link${JSON.stringify(items)}${actionAfterPayment}`;
  
  if(key.length < 100){
    var paymentLink = getCache(key);
    if (paymentLink) return paymentLink;
  }
  
  if(isURL(actionAfterPayment)){
    var response = postData('https://api.stripe.com/v1/payment_links', {
      ...Object.assign({}, ...lineItems),
      'after_completion[type]': 'redirect',
      'after_completion[redirect][url]': actionAfterPayment,
      'invoice_creation[enabled]': true, 
    });
    
  } else if(actionAfterPayment != "") {
    var response = postData('https://api.stripe.com/v1/payment_links', {
      ...Object.assign({}, ...lineItems),
      'after_completion[type]': 'hosted_confirmation',
      'after_completion[hosted_confirmation][custom_message]': actionAfterPayment,
      'invoice_creation[enabled]': true, 
    });
  }

  const url = response.url;
  
  if(key.length < 100){
    setCache(key, url);
  }

  return url;
}


function getPriceId(name, price = '1234', currency = 'USD') {
  const product_id = getProductId(name);
  const key = product_id + price + currency;
  const priceId = getCache(key);
  if (priceId) return priceId;
  const api = 'https://api.stripe.com/v1/prices';
  const { data = [] } = getData(api, { limit: 100, currency, product: product_id });
  const { id: newPriceId } =
    data.find(({ unit_amount }) => String(unit_amount) === String(price)) ||
    postData(api, { currency, product: product_id, unit_amount: price });
  setCache(key, newPriceId);
  return newPriceId;
}


function getProductId(name) {
  const productId = getCache(name);
  if (productId) return productId;
  const api = 'https://api.stripe.com/v1/products';
  const { data = [] } = getData(api, { limit: 100 });
  const { id: newProductId } =
    data.find(({ name: productName }) => productName === name) || postData(api, { name });
  setCache(name, newProductId);
  return newProductId;
}


function getData(endpoint, params) {
  const response = UrlFetchApp.fetch(`${endpoint}?${convertPayload(params)}`, {
    headers: {
      Authorization: `Bearer ${STRIPE_API_KEY}`,
    },
  });

  return JSON.parse(response);
}


function postData(endpoint, params) {
  const response = UrlFetchApp.fetch(endpoint, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${STRIPE_API_KEY}`,
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    payload: convertPayload(params),
  });

  return JSON.parse(response);
}


function convertPayload(params = {}) {
  return Object.entries(params)
    .map(([key, value]) => [encodeURIComponent(key), encodeURIComponent(value)].join('='))
    .join('&');
}


function isURL(str) {
  var httpsRegex = /^https:\/\//;
  return httpsRegex.test(str);
}


function getCache(key) {
  return CacheService.getScriptCache().get(key);
}


function setCache(key, value) {
  CacheService.getScriptCache().put(key, value, 21600);
}

It’s possible to extend this script to generate subscription payment links for recurring charges to customers.

Shares:

Leave a Reply

Your email address will not be published. Required fields are marked *