DEV Community

loading...
Cover image for Using Blockonomics Bitcoin Payments API

Using Blockonomics Bitcoin Payments API

aj54 profile image Ayush Jain Updated on ・5 min read

In this tutorial, we are going to use Blockonomics Payment API to receive Bitcoin payments on our website.

What is Blockonomics?

Blockonomics is a decentralized Bitcoin payment solution that provides you with specialized transactional tools to enhance your BTC use. With Blockonomics, you can generate Bitcoins by accepting it on your online stores, as well as utilitarian features such as creating P2P invoices, sending emails via Bitcoin, and tracking your wallet addresses.

What we’re building

We will create an online shop that will accept Bitcoin payments using Blockonomics Payment API. Let’s get started!

Tech Stack

  • Django
  • HTML/CSS
  • Javascript

Setting Up

Before getting started, you can set up the local version of this tutorial using github repository

git clone https://github.com/AJ-54/Blockonomics.git
pip install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

Make sure you have your Blockonomics API Key handy. To get one for free, create your account and get to this page.

Inside Blockonomics folder, go to settings.py file and place your API KEY to the API_KEY variable

python manage.py migrate
python manage.py runserver
Enter fullscreen mode Exit fullscreen mode

Now, if you go to http://127.0.0.1:8000, you will be able to see the same screen like that of https://blockonomics.herokuapp.com

The HTTP Callback URL

To use the Bitcoin payments API, you need to set up the order hook URL at your merchant page on the Blockonomics website. Every time a transaction carried on the address associated with your API key changes its status, Blockonomics will use the HTTP Callback URL provided by you to notify you about the status update. Also, new transaction notifications are also provided using the same HTTP Callback URL.

The Logic

In order to integrate Blockonomics payment API, you should know how the process works. Firstly, you need the Blockonomics account and your API Key. Next, you should use a unique Bitcoin address every time you do a transaction. You can request a new address using the New Address API. Once the buyer uses that Bitcoin address to transfer the amount, you will get the status update from Blockonomics on the HTTP Callback URL provided by you. Thus, your backend logic must process the requests received at that endpoint to classify the transactions.

Payments App

I have created a core Django application called payments which is responsible for everything.

Understanding Models

To store the information about the transactions, I created an Invoice table. The table looks like this

class Invoice(models.Model):
    STATUS_CHOICES = ((-1,"Not Started"),(0,'Unconfirmed'),
   (1,"Partially Confirmed"), (2,"Confirmed"))

    product = models.ForeignKey("Product", on_delete=models.CASCADE)
    status = models.IntegerField(choices=STATUS_CHOICES, default=-1)
    order_id = models.CharField(max_length=250)
    address = models.CharField(max_length=250, blank=True, null=True)
    btcvalue = models.IntegerField(blank=True, null=True)
    received = models.IntegerField(blank=True, null=True)
    txid = models.CharField(max_length=250, blank=True, null=True)
    rbf = models.IntegerField(blank=True, null=True)
    created_at = models.DateField(auto_now=True)
Enter fullscreen mode Exit fullscreen mode

The Invoice table stores the product for which the invoice is created, the address is the Bitcoin address used for this transaction. The btcvalue is the amount that you have charged from the buyer and received is the amount you receive from the buyer. Both these values will be in satoshi. The most important field is status which describes the current status of this transaction.

Creating Payment Invoice

Once the user clicks on the price button, we process the request inside create_payment view. The job here is to create a new object in the Invoice table and then redirect the request to the track_invoice view.

def exchanged_rate(amount):
    url = "https://www.blockonomics.co/api/price?currency=USD"
    r = requests.get(url)
    response = r.json()
    return amount/response['price']

def create_payment(request, pk):

    product_id = pk
    product = Product.objects.get(id=product_id)
    url = 'https://www.blockonomics.co/api/new_address'
    headers = {'Authorization': "Bearer " + settings.API_KEY}
    r = requests.post(url, headers=headers)
    print(r.json())
    if r.status_code == 200:
        address = r.json()['address']
        bits = exchanged_rate(product.price)
        order_id = uuid.uuid1()
        invoice = Invoice.objects.create(order_id=order_id,
                                address=address,btcvalue=bits*1e8, product=product)
        return HttpResponseRedirect(reverse('payments:track_payment', kwargs={'pk':invoice.id}))
    else:
        print(r.status_code, r.text)
        return HttpResponse("Some Error, Try Again!")
Enter fullscreen mode Exit fullscreen mode

HTTP Callback URL Endpoint

The receive_payment view is the endpoint for receiving status updates from Blockonomics. It is used to sync our Invoice table in the database with recent transactions and their status updates.

def receive_payment(request):

    if (request.method != 'GET'):
        return 

    txid  = request.GET.get('txid')
    value = request.GET.get('value')
    status = request.GET.get('status')
    addr = request.GET.get('addr')

    invoice = Invoice.objects.get(address = addr)

    invoice.status = int(status)
    if (int(status) == 2):
        invoice.received = value
    invoice.txid = txid
    invoice.save()
    return HttpResponse(200)
Enter fullscreen mode Exit fullscreen mode

Tracking Payment Invoice

You can track any invoice if you know the invoice ID. The track_invoice view fetches the latest data of that invoice ID from our database and passes it to the frontend. It also passes whether the user has paid the required amount, if yes then the paid variable is also passed to the frontend. At this point, you can add your business logic.

def track_invoice(request, pk):
    invoice_id = pk
    invoice = Invoice.objects.get(id=invoice_id)
    data = {
            'order_id':invoice.order_id,
            'bits':invoice.btcvalue/1e8,
            'value':invoice.product.price,
            'addr': invoice.address,
            'status':Invoice.STATUS_CHOICES[invoice.status+1][1],
            'invoice_status': invoice.status,
        }
    if (invoice.received):
        data['paid'] =  invoice.received/1e8
        if (int(invoice.btcvalue) <= int(invoice.received)):
            data['path'] = invoice.product.product_image.url
    else:
        data['paid'] = 0  

    return render(request,'invoice.html',context=data)
Enter fullscreen mode Exit fullscreen mode

Invoice Page Front End

In the frontend, we have displayed all the data we get from track_invoice view. But, when the transaction status gets updated, how will the buyer know about it?
To address this issue, we can either continuously pool our database to get the recent status of this invoice or we can use the WebSocket provided by Blockonomics. It is HIGHLY recommended to use WebSocket as continuous polling may have serious effects on system performance. Blockonomics pushes the status update through websocket as well, so your frontend will instantaneously know the changes, so you know that your page is now outdated. At this point, you can either reload the page to get recent data from track_invoice view or use AJAX calls to do the same. It is recommended to use a time out of 1 second, because receive_payment view will take some time to update the database with details and once you wait for a while, you are assured that your database is updated and thus you can perform the action.

var socket = new WebSocket("wss://www.blockonomics.co/payment/"+ address);
socket.onmessage = function(event){
  response = JSON.parse(event.data);
  //This condition ensures that we reload only when we get a 
  //new payment status and don't go into a loop
    if (parseInt(response.status) > parseInt(status))
    setTimeout(function(){window.location.reload() }, 1000); 
}
Enter fullscreen mode Exit fullscreen mode

The End

The video tutorial explaining the entire demo is attached below. In case you have queries, feel free to use the comment section!

Discussion (0)

pic
Editor guide