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
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 theAPI_KEY
variable
python manage.py migrate
python manage.py runserver
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)
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!
Top comments (0)