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:

  <script
    src="https://checkout.stripe.com/checkout.js"
    class="stripe-button"
    data-key="pk_test_YOUR_KEY_HERE"
    data-image="/cats.jpg"
    data-name="Cats fer Coins"
    data-description="2 cats ($20.00)"
    data-amount="2000"
    data-currency="usd"
    data-label="Pay with Bitcoin"
    data-bitcoin="true">
  </script>

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="https://checkout.stripe.com/checkout.js"></script>

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

<script>
  var handler = StripeCheckout.configure({
    key: 'pk_test_YOUR_KEY_HERE',
    image: 'http://i.imgur.com/00IK2nj.jpg',
    token: function(token) {
      // Use the token to create the charge with a server-side script.
      // You can access the token ID with `token.id`
    }
  });

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

  // Close Checkout on page navigation
  $(window).on('popstate', function() {
    handler.close();
  });
</script>

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="https://js.stripe.com/v2/stripe.js"></script>

<script type="text/javascript">
  Stripe.setPublishableKey('pk_test_YOUR_KEY_HERE');

  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(response.id, function() {
      // post response.id to your server to create a charge
    });
  }

  function filledReceiverHandler(

  Stripe.bitcoinReceiver.createReceiver({
    amount: 2000,
    currency: 'usd',
    description: 'Cats!',
    email: 'purrfect@catscatscats.cat'
  }, populateBitcoinCheckout);
</script>

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: 'purrfect@catscatscats.cat',
  description: 'Cats!',
  currency: 'usd',
  source: params[:bitcoin_receiver_id]
)

charge.source.amount
charge.source.inbound_address

Caveats

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.

Mastering Modern Payments

Build a Better Payment System

Get a free five part email course all about Stripe and Rails, including the first three chapters of Mastering Modern Payments.


No spam. Unsubscribe at any time.
Pete Keen Portrait Pete Keen has been professional software developer for a decade, building payment systems and other software for companies large and small. He blogs here and at petekeen.net.