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.

Related Whitepaper:

Software Architecture

This guide will introduce you to the world of Software Architecture!

This 162 page guide will cover topics within the field of software architecture including: software architecture as a solution balancing the concerns of different stakeholders, quality assurance, methods to describe and evaluate architectures, the influence of architecture on reuse, and the life cycle of a system and its architecture. This guide concludes with a comparison between the professions of software architect and software engineer.

Get it Now!  

Leave a Reply


8 − seven =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
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.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books