Accepting Bitcoin

Stripe supports accepting Bitcoin alongside payments from credit cards. This guide will help you get started with your integration.

An example of Bitcoin in Stripe Checkout.

With Stripe, you can accept Bitcoin in nearly the same way that you accept credit card payments. The key difference lies in how the payment is actually made.

With credit cards, you collect a card number from your customer. You can use this card number multiple times, but each time, the customer’s bank may choose to decline the charge. Simply collecting the card number does not guarantee access to any particular amount of funds.

With Bitcoin, there’s no saved number that you can attempt to charge multiple times or at a later date. Instead, you invert the process by telling your customer how much they need to pay you, and then provide a way for them to pay you that amount.

When you accept Bitcoin with Stripe:

  • You specify the amount that you want to collect from your customer in USD. We determine what amount of bitcoin (BTC) is needed to convert to your specified USD amount.
  • We create what is called a BitcoinReceiver—a wrapper around a Bitcoin address that provides a virtual location that your customer can push the payment to.
  • Once the customer has pushed enough bitcoin into the receiver, you can create a charge using this receiver (just as you would use a card token if you were accepting a credit card payment). Because the funds are already in the receiver when you create the charge, there’s no concept of a “decline” the way there would be when using a credit card. You already have the bitcoin, so creating a charge from the BitcoinReceiver cannot fail.

If you’re an existing Stripe user, you can likely start accepting Bitcoin payments without making a single change to your server-side integration: all API endpoints and dashboard reports support both Bitcoin and credit card payment types.

You currently need a US bank account to accept Bitcoin payments. Stripe users in more than twenty countries can attach a US bank account to their Stripe account, but we know it’s not ideal for non-US users, so we’re working to expand Bitcoin acceptance more broadly.

To process live Bitcoin payments, you need to enable the live Bitcoin API on your account

Quickstart Example

The simplest way to accept Bitcoin is to use Stripe Checkout. To enable Bitcoin in Checkout, simply add the data-bitcoin="true" option when loading Checkout, as follows:

<form action="/create_payment" method="POST">
  <script
    src="https://checkout.stripe.com/checkout.js" class="stripe-button"
    data-key="pk_test_6pRNASCoBOKtIshFeQd4XMUh"
    data-image="/square-image.png"
    data-name="Demo Site"
    data-description="2 widgets ($20.00)"
    data-amount="2000"
    data-currency="usd"
    data-bitcoin="true">
  </script>
</form>

If you’re already a Checkout user, this is the only code change you need to make to accept Bitcoin! You don’t need to worry about what amount in bitcoin you want to charge—you simply specify the amount of USD that you want to receive, and we’ll handle showing your customer how much BTC to pay.

Once the customer has sent the payment, Checkout submits the form and you can then create a charge on your server in much the same way that you would use a credit card token:

curl https://api.stripe.com/v1/charges \
   -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
   -d source=btcrcv_14ctSt2EftWUeI88LEvGiohr \
   -d amount=2000 \
   -d currency=usd

That’s all you need to get off the ground with accepting Bitcoin! In the sections below, we’ll cover both the client-side and server-side aspects of the integration in more detail.


Part 1: Generating a Bitcoin address for payment

As mentioned earlier, Bitcoin payments differ from credit card payments in that the customer needs to initiate the payment. Once you decide how much you’d like to charge, you can generate a Bitcoin address by creating a BitcoinReceiver—the returned object will include the converted bitcoin (BTC) amount to send and an inbound_address where the customer can send it to.

BitcoinReceiver objects here are treated very similarly to card tokens, but there are two major differences:

  • When Checkout or Stripe.js (via callback) passes a BitcoinReceiver back to the server, that receiver is “full”: the customer already sent bitcoin to the specified Bitcoin address, and the bitcoin was converted to USD. If you do not end up using the receiver to claim the payment, the funds will still be debited from the customer. (This is different from not using a card token, where the card will simply not get charged.)
  • Stripe does not currently support recurring or repeated payments with Bitcoin. The receivers can only be used for a single payment.

You can use either Stripe Checkout or Stripe.js to build your payment flow. We recommend Checkout, but Stripe.js allows for the most customization.

Using Checkout

In this guide we’re using the simple Checkout integration, but you can check out the main documentation for information on how to further customize Checkout.

To accept Bitcoin in addition to credit card charges, add a data-bitcoin="true" attribute to the Checkout <script> tag (as seen in the example above). Once a Bitcoin payment is received, Checkout will submit the form with the following extra fields: stripeToken, stripeTokenType (with a value of bitcoin_receiver), and stripeEmail.

To actually claim the payment, you’ll need to create a charge against that BitcoinReceiver via the API. This is explained in the next section.

Using Stripe.js

You should use Stripe.js if you want total control over your Bitcoin payment flow, but you’ll need to build your own user interface, polling logic, etc. (By contrast, Checkout provides all of this for you.)

Creating and displaying a BitcoinReceiver

First, create a BitcoinReceiver using Stripe.js with the amount in USD that you’d like to charge. The receiver will expose an amount in bitcoin (BTC) and an address that the customer can then send their payment to.

<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_6pRNASCoBOKtIshFeQd4XMUh');

  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.createReceiver({
    amount: 2000,
    currency: 'usd',
    description: 'Socks for [email protected]',
    email: '[email protected]'
  }, populateBitcoinCheckout);
</script>

At creation, Stripe guarantees an exchange rate for 10 minutes. If the customer sends bitcoin to the receiver after the 10 minutes have expired, we’ll still process the transaction but the conversion amount will no longer be guaranteed.

There are several pieces of information you should display to the customer:

  • bitcoin_amount: The amount that the customer must send. Note: The bitcoin amount (like all amounts returned by the API) is an integer. This amount is denominated in Satoshi. There are 10^8 (that is, 100,000,000) Satoshi in one bitcoin. You’ll want to divide the returned amount by 100,000,000 to present the amount in bitcoin.
  • inbound_address: The Bitcoin address that is specific to this receiver.
  • bitcoin_uri: An encoding of the amount and address. If you encode this URI as a QR code, many Bitcoin apps can scan it. If you present this URI as a hyperlink, many customers can click on it to activate their Bitcoin client (much like a mailto link).

Polling the BitcoinReceiver

Bitcoin payments are asynchronous: after generating the address, you need to wait for the customer to send the payment. We’ve provided a utility method that will help you poll the Stripe API for changes to the receiver.

Stripe.bitcoinReceiver.pollReceiver("btcrcv_3hwhfVWdCKxqi9", filledReceiverHandler);

The method takes in a callback as a second argument; when the requested amount is received (when receiver is “filled”), Stripe.js will call the specified handler. You can use this function to post the ID of the receiver to your server, along with any other necessary customer information.

Because a receiver’s guaranteed exchange rate expires after 10 minutes, you should keep track of how long it’s been displayed to the customer. Before 10 minutes elapse, you can create a new BitcoinReceiver and update the payment page with the new receiver’s information. You can then use Stripe.js to start polling the new receiver and cancel polling on the old one:

// Once 10 minutes have elapsed, create a new receiver and start polling it.
Stripe.bitcoinReceiver.createReceiver(...);
Stripe.bitcoinReceiver.pollReceiver(newID, filledReceiverHandler);

// Wait before canceling the old receiver in case the customer was already in
// the process of sending a payment to it.
setTimeout(function() {
    Stripe.bitcoinReceiver.cancelReceiverPoll("btcrcv_3hwhfVWdCKxqi9");
}, 60 * 1000);

Part 2: Creating a charge

When the receiver is filled (that is, has been sent the full amount of bitcoin to complete payment), the receiver should be submitted to your server for actual charge creation, as you would with a credit card token. This is the final step in completing the payment—if you don’t create a charge object using the receiver, you will not be paid the funds from the transaction.

There are a couple of important things to note about receivers:

  • A BitcoinReceiver can only be used if it has been filled, and can be used at most once.
  • The charge request must use the same amount and currency as the receiver. (You cannot charge less than the receiver amount.)

On the client side, the exchange rate for a BitcoinReceiver expires after 10 minutes. However, a filled BitcoinReceiver never expires since the bitcoin inside of it have already been converted to currency. That being said, you probably want to create a payment immediately after the receiver is filled.

Bitcoin receivers can also be linked to a Stripe customer object and used to create a charge for that customer. Just remember that you can only make one charge against the BitcoinReceiver attached to the customer, and that it must be for the same amount and currency as the BitcoinReceiver.

If you’re currently integrated with Stripe, you’ll notice that the receiver’s ID is passed as the source parameter. This is a change from the card parameter used to create credit card charges.

Similarly, charges created from a BitcoinReceiver have a source attribute rather than a card attribute. To avoid breaking your existing integration, you’ll need to make sure you update any charge retrieval code to look at the source property instead of the card property, since Bitcoin charges will not have a card attribute present.

Refunds

Like any other type of payment, you can refund Bitcoin charges through the dashboard or API:

However, with Bitcoin, you’ll need to provide the Bitcoin address to refund to. In most cases, this means that you need to collect a refund address from your customer.

When refunding a Bitcoin charge, the amount refunded must be at least $1. A status code of 400 will be returned in the case you try to refund a smaller amount.

Mispayments

The customer is responsible for sending the correct amount of bitcoin to fill the receiver. It is rare but possible that the customer will end up sending an unexpected amount. This is referred to as mispayment; the three basic possibilities are: (a) the customer sends too few bitcoin so you cannot “capture” the payment, (b) the customer sends too many bitcoin and needs to be partially refunded, or (c) the customer sends the correct amount of bitcoin but they send it belatedly or there’s a network error such that the receiver token is never posted to your server.

In case (c), you can defend against this easily by having your integration listen for bitcoin.receiver.filled webhooks and creating charges from those receivers.

The easiest way to handle mispayments is to ask Stripe to handle them on your behalf: if you pass refund_mispayments=true when creating a BitcoinReceiver, then Stripe will automatically refund any unused bitcoin one hour after the receiver is created. If no refund address is available for the customer, Stripe will contact them directly using the email address provided when creating the BitcoinReceiver. Stripe Checkout will also automatically refund mispayments one hour after creating a BitcoinReceiver.

If you prefer to handle mispayments yourself—which is the default if you do not provide a refund_mispayments flag—you can use webhooks to detect when a mispayment occurs (we will fire bitcoin.receiver.transaction.created events whenever someone pushes money to a receiver). You can also use the dashboard to manually look for receivers with unclaimed funds.

Webhooks

A successful Bitcoin payment generates the charge.succeeded webhook, which is the same as a successful credit card charge. There are also Bitcoin-receiver specific bitcoin.receiver.created, bitcoin.receiver.transaction.created, and bitcoin.receiver.filled webhooks to notify your server when any of these events have occurred. Refer to the webhooks documentation for more information on consuming webhooks.


Further Reading

You should now be able to accept Bitcoin payments! Some things you might want to look at next: