Bozhidar Bozhanov

About Bozhidar Bozhanov

Senior Java developer, one of the top stackoverflow users, fluent with Java and Java technology stacks - Spring, JPA, JavaEE. Founder and creator of Computoser and Welshare. Worked on Ericsson projects, Bulgarian e-government projects and large-scale online recruitment platforms.

How To Accept Bitcoin Payments

Bitcoin is gaining popularity, and last week I decided to implement it as a payment option for my computer-generated music service. Why I decided to do that is detailed here (payment is only needed for commercial use of the music), but here I’ll share the technical details for implementing the bitcoin integration.

First, you need to pick a payment gateway/provider. You can pick one from this list. They differ in terms of their API and specific flow, but the general flow should be almost the same. Some of the implementation details below are relevant only to what I picked up – Coinbase – but they should be similar for other providers. I picked Coinbase, because it seemed the most developer-friendly and straightforward. It has one bug that I had to workaround, but apart from that it’s ok.

The general flow (probably containing some Coinbase specifics) is below. Note that I am describing the most complex scenario, where you have multiple items with variable prices and quantities. You can use the html/js code I used in my cart page. On the other hand, it’s assuming a best-case payment provider that does not redirect the user to external pages and uses simply a javascript dialog.

  1. Place a custom “Pay with Bitcoin” button on the checkout page
  2. Clicking it submits a form and thus triggers a back-end checkout process
  3. The back-end code saves a new purchase/order in the database and returns its id
  4. Then the back-end code invokes the payment gateway API, providing the order id (or any custom application data) and the price, and gets a code to identify the transaction
  5. The price can be provided in BTC or any currency. Depending on the API, you may want/need to convert a fixed price in a popular currency to BTC before passing it via the API. If you do so, be sure to cache the conversion rates for a while – no need to fetch them every time. Providers may do this conversion automatically, but if you want to display it to the user first, you may want to do the conversion yourself.
  6. On returning the code to the front-end, the javascript gets it, and opens a dialog (using a js function/event provided by the provider).
  7. The dialog may contain multiple payment options, but it usually shows a bitcoin payment address to which the user should send the money. He can do that with his mobile or desktop wallet
  8. After the transaction is completed, a callback URL is invoked on your application, which contains the order id that you passed when generating the code. Then you can confirm the purchase and send the items purchased.
  9. Then the dialog is automatically closed (or the user presses “transaction complete”). At that point you need to send an (ajax) request that clears the cart contents, and redirect to a “Thank you” page.

Note that the documentation of the payment provider should provide all the implementation details. Below I’ll share some specifics of my case: Coinbase and Java:

The default scenario described in the docs is to put a button with a predefined code on the page. That doesn’t work if you need to increase quantities or have multiple items. That’s why you should dynamically generate the button code. But the javascript library only handles this on page load. So I had to copy some minified javascript code and invoke it when the code is returned from the back-end. Here is the whole javascript code (invoked when the user presses “Pay with bitcoin”):

$(document).ready(function() {
  $('#payWithBitcoin').click(function() {
      var email = $('#email').val();
      if (${!userLoggedIn} && (!email || email.length == 0 || email.indexOf('@') == -1)) { // simple validation here; actual - on the server
          alert('Please enter a valid email');
      } else {
          $.post('${root}/cart/bitcoinCheckout', {email: email}, function(data) {
              $('#bitcoinPurchase').attr('data-code', data);
              $('.coinbase-button').each(function (b, d) {
                  var f, g, h, i, j, k;
                  return f = $(d), h = f.data(), h.referrer = document.URL, j = $.param(h), g = f.data('code'), k = f.data('width') || 195, i = f.data('height') || 46, f.data('button-style') !== 'none' && f.replaceWith('<iframe src='' + c + '/buttons/' + g + '?' + j + '' id='coinbase_button_iframe_' + g + '' name='coinbase_button_iframe_' + g + '' style='width: ' + k + 'px; height: ' + i + 'px; border: none; overflow: hidden;' scrolling='no' allowtransparency='true' frameborder='0'></iframe>'), $('body').append('<iframe src='https://coinbase.com/buttons/' + g + '/widget?' + j + '' id='coinbase_modal_iframe_' + g + '' name='coinbase_modal_iframe_' + g + '' style='background-color: transparent; border: 0px none transparent; overflow: hidden; display: none; position: fixed; visibility: visible; margin: 0px; padding: 0px; left: 0px; top: 0px; width: 100%; height: 100%; z-index: 9999;' scrolling='no' allowtransparency='true' frameborder='0'></iframe>');
              });
              $('#coinbase_modal_iframe_' + data).load(function() {
                  $(document).trigger('coinbase_show_modal', data);
              });
          });
      }
  });

  $(document).on('coinbase_payment_complete', function(event, code){
      $.post('${root}/cart/clear', function() { //clear the contents of the cart
          window.location = '/?message=Checkout successful. Check your email.';
      });
  });
});
    <a id='payWithBitcoin' href='javascript:void(0);'><img src='${staticRoot}/img/bitcoin.png'/></a>
    <div class='coinbase-button' id='bitcoinPurchase' data-button-style='none'></div>
    <script src='https://coinbase.com/assets/button.js' type='text/javascript'></script>

Another thing to have in mind is that there are no official clients – you need to invoke the RESTful API manually. This is simple, of course. You can use a RestTemplate and Jackson, for example.

public String getButtonCode(BigDecimal price, long purchaseId) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        ButtonRequest buttonRequest = new ButtonRequest(); //this is a value-object specifically defined for this request
        buttonRequest.setCurrency('btc');
        buttonRequest.setCustom(String.valueOf(purchaseId));
        buttonRequest.setPrice(price.toPlainString());
        buttonRequest.setType('buy_now');
        buttonRequest.setName('Computer-generated tracks');
        ResponseEntity<String> entity = template.postForEntity('https://coinbase.com/api/v1/buttons?api_key=' + coinbaseKey, buttonRequest, String.class);
        String json = entity.getBody();

        try {
            JsonNode node = jsonMapper.readTree(json);
            return node.get('button').get('code').asText();
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
}

And finally, when the callback URL is invoked, you need to get the order id and finalize the payment:

    @RequestMapping('/confirmBitcoinPurchase')
    @ResponseBody
    public void confirmBitcoin(@RequestBody String json) throws Exception {
        JsonNode root = mapper.readTree(json);
        JsonNode order = root.get('order');
        if (order.get('status').asText().equals('completed')) {
            String paymentId = order.get('id').asText();
            .....
        }
     }

Overall, it takes some time to figure out. Previous experience with payment provider integration would be a plus, but there’s one important difference – you do not submit anything user-specific to the payment provider (like credit-card details). Instead, the user makes the payment to a target bitcoin address, which is handled by the payment provider. Whenever the transaction is complete, the provider invokes your URL. Then you can get your money from the payment gateway either via a bank transfer, or by transferring them to your own bitcoin wallet.
 

Reference: How To Accept Bitcoin Payments from our JCG partner Bozhidar Bozhanov at the Bozho’s tech blog blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


× 3 = eighteen



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close