Using Blockonomics Bitcoin Payments API
Tags: beginners, django, javascript, python
Published: 2021-01-23 16:24:58

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](https://www.blockonomics.co/views/api.html#payments). 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](https://github.com/AJ-54/Blockonomics)
```
git clone https://github.com/AJ-54/Blockonomics.git
pip install -r requirements.txt
```
Make sure you have your Blockonomics API Key handy. To get one for free, [create your account](https://www.blockonomics.co/register#) and get to [this](https://www.blockonomics.co/merchants) 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
```
Now, if you go to [http://127.0.0.1:8000](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](https://www.blockonomics.co/merchants#/page3) 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](https://www.blockonomics.co/views/api.html#newaddress). 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)
``` 
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!")
```
### 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)
```
### 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)
```
### 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); 
}
```

## The End

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