Mastering Modern Payments
The Mastering Modern Payments Blog

Collecting Taxes With Stripe

"How do I collect taxes with Stripe?"

If you're in a state/country where you have to collect sales taxes, I'm sure you've asked this question. Thankfully, Stripe makes it simple. All you have to do is update one attribute on your customers' Stripe::Subscription and it's done.

To automatically collect taxes from your customers, just set the tax_percent attribute, like this:

customer = Stripe::Customer.retrieve('cu_123abc')
sub = customer.subscriptions.retrieve('sub_123abc')

sub.tax_percent = 5

When Stripe attempts to pay this customer's next invoice the first time, they'll automatically calculate how much tax to add on. You'll see this amount in the tax attribute of the Stripe::Invoice, as well as being included in the amount_due and total attributes:

inv = Stripe::Invoice.retrieve('inv_12345')

inv.subtotal #=> 500
inv.tax_percent #=> 5 #=> 25
inv.amount_due #=> 525

You also have the option of not using tax_percent and instead tacking on an invoice item in response to invoice.created webhook events, but that has some significant drawbacks. First, you have to actually build the code to make that happen. Second, depending on where you're located, the tax you tack on this way won't be properly reported to your tax agency, nor will it be simple to extract when you're showing invoices to customers and looking at your data in reporting tools like Baremetrics or FirstOfficer.

One more thing to note: tax_percent only works for Stripe subscriptions. If you're making one-time charges you'll have to calculate the tax as appropriate and add it to the amount you're charging manually.

How to check CVC and Address with stripe.js

Someone recently asked on the Stripe API discussion mailing list:

"Does the Stripe.card.createToken call return back values for address_line1_check, address_zip_check, or cvc_check?"

Stripe Checkout has built-in behavior that runs these checks if you've provided that information and if you provide an amount. These checks work by asking the card network to authorize an amount on a particular card, but that amount doesn't get charged until you actually create a Stripe::Charge (see The Life of a Stripe Charge for full details on how this works).

It turns out, plain vanilla stripe.js that you use to construct custom forms also has this ability, but it's completely undocumented. All you have to do is pass an amount as the second parameter to the createToken call, like this:

  number: '4242424242424242',
  exp_month: '12',
  exp_year: '2022',
  cvc: '987'
}, 100, stripeResponseHandler);

There's two important caveats here:

  • This doesn't protect you against the card getting declined when you go to charge the card later. All it says is that this card can be charged right now.
  • This is completely undocumented, which means it could potentially break on you at any time.

That said, it's very useful to be able to run these checks ahead of time in a custom form.

Thanks to Matt Arkin for the original answer on the mailing list and for being a tremendous help in the Stripe community.

How do I immediately prorate subscription upgrades?

Normally when a customer upgrades their subscription Stripe will tack on a proration amount to their next invoice. They'll be able to use the upgraded service without actually paying for it. What if you want to prorate the customer's subscription right away? That is, you don't want to wait until the next billing cycle to start, you want to collect the proration amount from them immediately.

With Stripe's new ability to preview subscription updates this becomes pretty easy. First, get the preview amount like in the previous post:

upcoming = Stripe::Invoice.upcoming(
    customer: customer_id, 
    subscription: subscription_id,
    subscription_plan: 'monthly_25'

proration_amount = upcoming.lines.last.amount

Now that you have the amount, you can easily create a new invoice, immediately pay it, and upgrade the customer without proration:

customer = Stripe::Customer.retrieve(customer_id)
sub = customer.subscriptions.retrieve(subscription_id)

item = Stripe::InvoiceItem.create(
  customer: customer_id,
  subscription: subscription_id,
  amount: proration_amount

invoice = Stripe::Invoice.create(
  customer: customer_id,
  subscription: subscription_id

invoice =

if invoice.paid
  sub.plan = 'monthly_25'
  sub.prorate = false
  invoice.closed = true

The logic around the paid attribute above is important, because if the payment fails for some reason you don't want to upgrade the subscription, and you also don't want that invoice to retry automatically. This logic ensures that a customer who's payment fails won't get extra free services while Stripe's automatic retries are happening.

Previewing Subscription Upgrades

This question comes up a lot on the Stripe API discussion mailing list:

"Is there a way to see what Stripe will calculate the pro-rated amount to be prior to creating the invoice?"

Let's say you have a Stripe customer who wants to upgrade from a $5 monthly plan to a $25 monthly plan. Great! All you have to do is update their subscription's plan with the new plan id:

customer = Stripe::Customer.retrieve(customer_id)
sub = customer.subscriptions.retrieve(subscription_id)

sub.plan = 'monthly_25'

On their next billing period, the customer will see a new $25 charge as well as a proration of the last month's charge, which shows up as an invoice item. Determining what that amount would be on invoice item yourself is tricky and involves some guess work. You had to calculate a formula like this:

p = fraction of time left on current subscription
credit = p * current_subscription_price
debit = p * new_subscription_price
proration_amount = debit - credit

The guess work comes in around what value p should have, since Stripe calculates down to the second.

Previewing Updates

A few weeks ago the good folks at Stripe added a way to get Stripe to do the calculation for you, so you don't have to resort to calculating it yourself. For existing customers you can preview the next invoice that they'll get. This isn't new functionality, but what is new is that you can add a bunch of parameters to influence what the invoice would look like with those changes. Here's what that would look like for the customer above:

upcoming = Stripe::Invoice.upcoming(
    customer: customer_id, 
    subscription: subscription_id,
    subscription_plan: 'monthly_25'

puts upcoming.subtotal # => 2500 + the proration amount
puts upcoming.lines.first.amount # => 2500
puts upcoming.lines.last.amount # => proration amount

Using this you can display to the customer exactly what their next invoice will look like before they upgrade or downgrade.

Charging Customers with Bitcoin

What the heck is Bitcoin?

Bitcoin is a way to move money around without using official government currencies. In technical terms, it's a globally distributed piece of shared memory implemented as a chain of transactions contained within blocks. Each block cryptographically links to it's parent block, constructing a huge singly-linked list. If you're interested in the more technical or political aspects of Bitcoin, there is a very active subreddit.

Recently Stripe added support for accepting bitcoin in a way that makes sense for merchants who don't normally deal in the cryptocurrency world. Here's how it works:

  • When a customer wants to pay you in Bitcoin, Stripe will generate an address and calculates an amount of bitcoins that equals the price you set in your home currency.
  • The customer sends the correct amount of bitcoin to that address.
  • Stripe picks up the bitcoin and immediately converts it into your home currency for you. You can then create a Stripe::Charge using that pool of money instead of a credit card.

Using Bitcoin with Stripe Checkout

Stripe has made it very simple to use this new flow with Checkout. Basically you just have to add one new data attribute to your javascript embed: "data-bitcoin=true", and Stripe will take care of everything else.

Here's a little example:

    data-name="Cats fer Coins"
    data-description="2 cats ($20.00)"
    data-label="Pay with Bitcoin"

It's just as simple with a custom integration as well. Here's another example, this time using the JS API to launch the Checkout modal dialog:

<script src=""></script>

<button id="customButton">Purchase</button>

  var handler = StripeCheckout.configure({
    key: 'pk_test_YOUR_KEY_HERE',
    image: '',
    token: function(token) {
      // Use the token to create the charge with a server-side script.
      // You can access the token ID with ``

  $('#customButton').on('click', function(e) {
    // Open Checkout with further options{
      name: 'Cats fer Coins',
      description: '2 Cats',
      amount: 2000,
      bitcoin: true

  // Close Checkout on page navigation
  $(window).on('popstate', function() {

Using Bitcoin with a Custom Form

Allowing your customers to pay with bitcoin using a custom form is a little bit more complicated. Within your JS you have to create a BitcoinReceiver object, which is the thing that actually calculates the right amount of bitcoin as well as generates an address. After you present these two things to the customer, you need to poll the receiver and wait for the customer to pay. Here's what that looks like:

<div id="bitcoin_address"></div>
<div id="error_response"></div>

<script src=""></script>

<script type="text/javascript">

  function populateBitcoinCheckout(status, response) {
    if (status === 200) {
      document.getElementById("bitcoin_address").innerHTML = response.inbound_address;
    } else {
      document.getElementById("error_response").innerHTML = JSON.stringify(response);

    Stripe.bitcoinReceiver.pollReceiver(, function() {
      // post to your server to create a charge

  function filledReceiverHandler(

    amount: 2000,
    currency: 'usd',
    description: 'Cats!',
    email: ''
  }, populateBitcoinCheckout);

Making Charges

Actually charging the customer is very straightforward. All you have to do is pass the bitcoin receiver token to source, instead of a credit card token and proceed as normal. If you're saving information about the customer to your database (last 4 digits of their card, expiration date, etc), remember that a BitcoinReceiver has a different API than a card so you have to call different methods.

charge = Stripe::Charge.create(
  amount: 2000,
  email: '',
  description: 'Cats!',
  currency: 'usd',
  source: params[:bitcoin_receiver_id]



There are a few things to remember when you're dealing with Bitcoin. First, it can't be used for subscriptions, since there's no way to pull from a customer's bitcoin wallet. Bitcoin is pushes only. Second, refunds are a little bit tricker than what you may be used to with credit cards. To refund, you need to ask the customer for a refund address to send the bitcoin to. Other than that, the process is pretty standard. The amount is drawn out of your Stripe account, converted to bitcoin using the current exchange rate, and sent to the return address provided.

MMP v2.0.9 released

I just pushed v2.0.9 of Mastering Modern Payments. Here's a summary of the changes:

  • Add a note to add /app/services to the autoload path
  • Add some missing syntax highlighting that was causing problems with the PDF
  • Add some more instructions on how to create subscriptions and plans
  • Fix a busted link to Bootstrap
  • Explain some more options for setting up SSL
  • Run spell-check across the whole book and fix all the errors

Thanks to everyone who sent in bug reports and typos! Now with baked-in spell checking you'll never have to suffer through another 'emapil' again :)

Idempotent Stripe Requests

Since the beginning, Stripe has had an easy-to-use API. This didn't make it safe, though. Every time you make a POST request to Stripe, you're changing something. Sometimes this is innocuous, but often it's vitally important that this thing happen once and only once. For example, creating new charges, subscriptions, and customers should ideally only happen once. This is now possible with a new Stripe feature named Idempotency.

2015 Modern Payment Provider Roundup

Your business has to get paid, but how that happens is a complicated question, and the modern payment landscape is vast. How do you pick?

What payment service is the best fit for your business?

This list highlights the biggest modern payment providers in the market, where "modern" includes features like integrated merchant account and gateway services, RESTful APIs, and well maintained SDKs.

You can use this list to help you narrow down the choices for your business.

Stripe removed SSLv3 support. Here's how to fix the HTTP 401 errors.

On November 15th Stripe deprecated SSLv3 because of the POODLE vulnerability. On the whole, this has been a good and welcome change, because SSLv3 has been terrible for a very long time.

The problem is that on some systems this causes backend API requests to start failing with an error message from Stripe because they're unable to auto-negotiate TLSv1.2.

Stripe Account Balances for Service Credits

Say you want to give a customer an account credit for some reason. They're an especially good customer, or your service was down for a few minutes and you want to give service credits, or some other reason. You can do this using Stripe's account_balance feature.

Using Stripe Checkout for Subscriptions

Stripe provides a gorgeous pre-built credit card form called Stripe Checkout. Checkout is mainly intended for one-off purchses like Dribbble or my book. Many people want to use it for their Stripe-powered subscription sites so in this article I'm going to present a good way of doing that.

The Life of a Stripe Charge

One of the most common issues that shows up in the #stripe IRC channel is people setting up their front-end Stripe Checkout integration and then expecting a charge to show up, which isn't really how Stripe works. In this post I'm going to walk through a one-off Stripe charge and hopefully illustrate how the whole process comes together.

Shipping with Stripe and EasyPost

Let's say that instead of running a Software as a Service, you're actually building and shipping physical products. Let's say quadcopter kits. People come to your website, buy a quadcopter kit, and then you build it and ship it to them. It takes you a few days to build the kit, though, and you would rather not charge the customer until you ship. Traditionally Stripe has been focused on paying for online services but recently they added the ability to authorize and capture payments in two steps. In this post we're going to explore billing with Stripe and shipping with EasyPost with separate charge and capture.

Design for Failure: Processing Payments with a Background Worker

Processing payments correctly is hard. This is one of the biggest lessons I've learned while writing my various SaaS projects. Stripe does everything they can to make it easy, with quick start guides and great documentation. One thing they really don't cover in the docs is what to do if your connection with their API fails for some reason. Processing payments inside a web request is asking for trouble, and the solution is to run them using a background job.

Join Our Newsletter

RSS Feed

Buy the Book
Learn More