Change Stripe subscription default payment method?

I am working on an app that uses the anvil.stripe module to create a Stripe subscription. I see a way to create a customer and start the subscription. I also see how you can add a new payment method to a customer using customer.add_token(token).

However, when I add a new payment method to an existing customer, I don’t see a way that I can change the newly added payment method to be the default payment method for the customer. How should I handle the situation where an existing customer wants to update the payment method they are using for a subscription?

Hi Nate, welcome to the forum!

After creating a customer and storing their stripe_id in your ‘Users’ data table, and adding a payment method using customer.add_token(token), you can access a customer’s default payment method like this:

customer = anvil.stripe.get_customer(user['stripe_id'])
customer['default_source']

(see the stripe reference docs for details on the full Customer object).

To modify a customer’s default payment method, you’ll need to use the official Stripe Python API from your Server Modules (you’ll need to be on one of our full Python runtimes to do this).

For example, if you store your secret Stripe API key using Anvil’s App Secrets as ‘stripe_key’, you can modify the Customer object using the Stripe API directly, like this:

  stripe.api_key = anvil.secrets.get_secret('stripe_key')
  stripe.Customer.modify(
      user['stripe_id'],
      default_source=source_id
  )

You can find the appropriate source_id by accessing your customer’s sources, like this:

user = anvil.users.get_user()
customer = anvil.stripe.get_customer(user['stripe_id'])
print("customer's sources: %s" % customer['sources'])

I hope this helps!

1 Like

Thank you for your response, and it was helpful. I was able to make this work by following the steps you outlined, with one change. I had to use the full stripe API to get the customer sources instead of anvil.stripe. With your code above, the server code execution timed out when I tried to read the data in customer['sources']. Instead I did this:

customer = stripe.Customer.retrieve(user['stripe_id'])
sources = customer['sources']

Anyway, I know it has been some time since the original question, but I have one follow up question now.

When I use stripe.checkout.get_token() on the client to obtain a token associated with a new card for updating the default_source on the server, the form that pops up to collect the information has a button labeled Pay when you collect the card details. This button is a bit misleading because get_token() doesn’t actually charge anything to the card when you click this button.

Is there a way that I can change this button text to something like Update Card instead of Pay? That would make it much more clear to the user what is actually happening.

Hi @nate,

Glad to hear you got it all working. We don’t currently support changing the text in the Pay button - can I ask you to post this in Feature requests?