Skip to content

Instantly share code, notes, and snippets.

@mikegogulski
Last active October 11, 2024 14:45
Show Gist options
  • Save mikegogulski/83ce5f6ac0633ca6cac913d0dab4b9eb to your computer and use it in GitHub Desktop.
Save mikegogulski/83ce5f6ac0633ca6cac913d0dab4b9eb to your computer and use it in GitHub Desktop.
Copy Stripe production products and prices to test environment
### The best way to start is to use the "Delete all test data" button at https://dashboard.stripe.com/test/developers
### Setup:
import stripe
test = 'sk_test_51IXXXyoursecretkey'
prod = 'sk_live_51IXXXyoursecretkey'
skip_fields = ['amount_decimal', 'unit_amount_decimal', 'type', 'object', 'created', 'livemode', 'updated',]
ignore_products = ['prod_JNXXXyourproductID',]
### Fetch production products and prices
stripe.api_key = prod
prodproducts = ('Product', stripe.Product.list(active=True))
prodprices = ('Price', stripe.Price.list(active=True))
stripe.api_key = test
### Define some functions
def clear_stripe_things(thing: tuple) -> None:
'''
Clear out test products/prices
'''
print('Clearing', thing[0])
for p in getattr(stripe, thing[0]).list():
print('Clearing', p.get('id'), '-', p.get('name'))
if p.get('product') in ignore_products:
print('Ignoring')
continue
if not p.get('active'):
print('Inactive, skipping')
continue
if p.get('livemode'):
print('LIVE MODE THING! Skipping')
continue
try:
getattr(stripe, thing[0]).modify(p.get('id'), active=False)
except Exception as e:
print('Exception modifying for', p)
print(e)
pass
try:
p.delete()
except Exception as e:
print('Exception deleting for', p.get('id'))
print(e)
continue
def upload_products() -> None:
'''
Copy production products to test, preserving IDs
'''
print('Uploading products')
up = list()
for p in prodproducts[1].get('data'):
print('Queueing', p.get('id'), '-', p.get('name'))
if p.get('product') in ignore_products:
print('Ignoring')
continue
up.append({k:v for k,v in p.items() if k not in skip_fields})
for p in up:
try:
print('Uploading', p.get('id'), '-', p.get('name'))
print(up)
stripe.Product.create(**p)
except Exception as e:
print('EXCEPTION creating', p)
print('EXCEPTION:', e)
continue
def get_by_kv(lis, k, v):
'''
Return first element in list where key, value matches k, v in dictionary
'''
for e in lis:
if e.get(k) == v:
return e
def upload_prices() -> None:
'''
Upload prices to Stripe, preserving product ID correspondences
'''
skips = skip_fields + ['id']
for p in prodproducts[1]:
print('Uploading for', p.get('id'), '-', p.get('name'))
if not p.get('active'):
print('Inactive product, skipping')
continue
# x = get_by_kv(prodprices[1], 'product', p.get('id'))
# print(x)
prod_price = get_by_kv(prodprices[1], 'product', p.get('id'))
print('prod_price', prod_price)
test_price = {k:v for k,v in prod_price.items() if k not in skips}
print('test_price', test_price)
try:
stripe.Price.create(**test_price)
except Exception as e:
print('EXCEPTION creating price', p)
print('EXCEPTION:', e)
continue
stripe.api_key = test
clear_stripe_things(prodprices)
clear_stripe_things(prodproducts)
stripe.api_key=test
upload_products()
upload_prices()
@AachoLoya
Copy link

not working...keep getting Exception messages. I'm using latest API level

@mikevendelux
Copy link

Sorry about that. I'm not developing for Stripe anymore, unfortunately.

@AachoLoya
Copy link

No worries, left a comment so future readers would know that it won't work with latest stripe API version

@cunneen
Copy link

cunneen commented Aug 23, 2023

Thanks for this @mikegogulski . We're using tiered (graduated) pricing, and with some minor tweaks and the old stripe API version (v2.70.0), it happily copied the products and pricing over. Changes:

  • Added an expand=['data.tiers'] parameter to the call to stripe.Price.list(...)
  • Added unit_amount_decimal and flat_amount_decimal to the skip_fields array for the prices.
  • Deleted the (nested) unit_amount_decimal and flat_amount_decimal from each item in the tiers array of a price.
  • Set the up_to property of a tier to 'inf' if it isn't set.
pip install stripe==2.70.0

With the updates described above:

### The best way to start is to use the "Delete all test data" button at https://dashboard.stripe.com/test/developers

### Setup:

import stripe

test = 'sk_test_51IXXXyoursecretkey'

prod = 'sk_live_51IXXXyoursecretkey'

skip_fields = ['amount_decimal', 'unit_amount_decimal', 'type', 'object', 'created', 'livemode', 'updated',]
ignore_products = ['prod_JNXXXyourproductID',]

### Fetch production products and prices

stripe.api_key = prod
prodproducts = ('Product', stripe.Product.list(active=True))
prodprices = ('Price', stripe.Price.list(active=True, expand=['data.tiers']))
stripe.api_key = test

### Define some functions

def clear_stripe_things(thing: tuple) -> None:
  '''
  Clear out test products/prices
  '''
  print('Clearing', thing[0])
  for p in getattr(stripe, thing[0]).list():
    print('Clearing', p.get('id'), '-', p.get('name'))
    if p.get('product') in ignore_products:
      print('Ignoring')
      continue
    if not p.get('active'):
      print('Inactive, skipping')
      continue
    if p.get('livemode'):
      print('LIVE MODE THING! Skipping')
      continue
    try:
      getattr(stripe, thing[0]).modify(p.get('id'), active=False)
    except Exception as e:
      print('Exception modifying for', p)
      print(e)
      pass
    try:
      p.delete()
    except Exception as e:
      print('Exception deleting for', p.get('id'))
      print(e)
      continue


def upload_products() -> None:
  '''
  Copy production products to test, preserving IDs
  '''
  print('Uploading products')
  up = list()
  for p in prodproducts[1].get('data'):
    print('Queueing', p.get('id'), '-', p.get('name'))
    if p.get('product') in ignore_products:
      print('Ignoring')
      continue
    up.append({k:v for k,v in p.items() if k not in skip_fields})
  for p in up:	
    try:
      del p['default_price']
      print('Uploading', p.get('id'), '-', p.get('name'))
      print(up)
      stripe.Product.create(**p)
    except Exception as e:
      print('EXCEPTION creating', p)
      print('EXCEPTION:', e)
      continue


def get_by_kv(lis, k, v):
  '''
  Return first element in list where key, value matches k, v in dictionary
  '''
  for e in lis:
    if e.get(k) == v:
      return e
  

def upload_prices() -> None:
  '''
  Upload prices to Stripe, preserving product ID correspondences
  '''
  skips = skip_fields + ['id','unit_amount_decimal','flat_amount_decimal']
  for p in prodproducts[1]:
    print('Uploading for', p.get('id'), '-', p.get('name'))
    if not p.get('active'):
      print('Inactive product, skipping')
      continue
    # x =	get_by_kv(prodprices[1], 'product', p.get('id'))
    # print(x)		
    prod_price = get_by_kv(prodprices[1], 'product', p.get('id'))
    # remove the "flat_amount_decimal" and "unit_amount_decimal" keys from the tiers
    #
    for tier in prod_price.get('tiers'):
      del tier['flat_amount_decimal']
      del tier['unit_amount_decimal']
      tier['up_to'] = 'inf' if tier.get('up_to') == None else tier.get('up_to')
    print('prod_price', prod_price)
    test_price = {k:v for k,v in prod_price.items() if k not in skips}
    print('test_price', test_price)
    try:
      stripe.Price.create(**test_price)
    except Exception as e:
      print('EXCEPTION creating price', p)
      print('EXCEPTION:', e)
      continue


stripe.api_key = test
clear_stripe_things(prodprices)
clear_stripe_things(prodproducts)


stripe.api_key=test
upload_products()
upload_prices()

@tomekit
Copy link

tomekit commented Oct 11, 2024

It seems to copy only monthly/default price. Is it possible to copy all prices associated with the product?

@mikevendelux
Copy link

@tomekit No doubt it is possible, but I'm not working with Stripe anymore so that feature won't be added here any time soon (or ever).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment