Payments API Integration in PHP

In this tutorial, we will understand how to integrate blockonomics payments API in a PHP-based shopping cart.

Resources

Source Code https://github.com/blockonomics/Demo-PHP-Application
Youtube Videohttps://www.youtube.com/watch?v=dibw1sGz3to

Tech Stack

  • PHP
  • HTML/CSS
  • Javascript

Setting Up

Complete the setup using the instructions provided here.

The Logic

The Database

The Database is going to have four different Tables namely invoices, orderes, payments and products. Each table plays a crucial role in the application.

The Application Database

The invoice table stores all the invoices. It has an id, code, address, price which is the USD price, status, product and ip columns. The IP column can help us to identify which invoices belong to the current user. The code is essentially the unique identifier for each invoice.

The invoice table

The payments table stores information about all the payments. It keeps track of the transaction id (txid), bitcoin address, value in satoshi and the status of the payment.

The payments table

Understanding the Code

The Project Code hierarchy is as follows –

- check
- css
buy.php
config.php
functions.php
getprice.php
index.php
invoice.php
orders.php
  • The check folder is used to store the callback from the Blockonomics.
  • The css folder contains the styles.
  • buy.php is the file we use to redirect the user to invoice page. It is responsible for creating the invoice.
  • config.php file stores the Blockonomics configuration. You can store all API’s and other key-value pairs here.
  • functions.php contains bunch of different functions that we use inside our application.
  • getprice.php simply returns the btc price for given USD.
  • index.php which is the homepage and contains all products.
  • invoice.php which is the invoice page and contains the blockonomics websocket.
  • orders.php which displays the orders of the user.

Currency Conversion

Inside getprice.php we get the current invoice price which is in USD and convert it to BTC.

<?php
include_once "functions.php";
$invoice = $_REQUEST['code'];
$price = getInvoicePrice($invoice);
$price = USDtoBTC($price);
echo $price*100000000;
?>

The functions getInvoicePrice and USDtoBTC are present inside the functions.php which is included at the very top in code.

New Address Generation

To generate a new bitcoin address, you have to use Blockonomics API which is documented here. We can see the function generateAddress which uses this API to generate new address.

function generateAddress(){
    global $apikey;
    global $url;
    $options = array( 
        'http' => array(
            'header'  => 'Authorization: Bearer '.$apikey,
            'method'  => 'POST',
            'content' => '',
            'ignore_errors' => true
        )   
    );  
    
    $context = stream_context_create($options);
    $contents = file_get_contents($url."new_address", false, $context);
    $object = json_decode($contents);
    
    // Check if address was generated successfully
    if (isset($object->address)) {
      $address = $object->address;
    } else {
      // Show any possible errors
      $address = $http_response_header[0]."\n".$contents;
    }
    return $address;
}

HTTP CallBack Request

Blockonomics uses the HTTP CallBack URL provided by you to send notifications about the payment status updates. The documentation provides a brief description about parameters of this request. We have implemented the callback endpoint inside the index.php file present in check folder.

<?php
/*
Callback location, set this in blockonmics merchant page
For testing payments locally, use this:
localhost/bitcoin/check?secret=asecretcode&addr=[ADDRESS]&status=[STATUS CODE]&txid=[TXID]&value=[Amount paid in satoshi]
*/
include_once "../config.php";
include_once "../functions.php";

$secretlocal = "asecretcode"; // Code in the callback, make sure this matches to what youve set

// Get all these values
$status = 0;
$txid = $_GET['txid'];
$value = $_GET['value'];
$status = $_GET['status'];
$addr = $_GET['addr'];
$secret = $_GET['secret'];

// Check all are set
if(empty($txid) || empty($value) || empty($addr) || empty($secret)){
    exit();
}

if($secret != $secretlocal){
    exit();
}


$sql = "INSERT INTO `payments` (`txid`, `value`, `addr`, `status`)
VALUES ('$txid', '$value', '$addr', '$status')";
mysqli_query($conn, $sql);
echo $sql;
// Get invoice price
$code = getCode($addr);
$price = getInvoicePrice($code);
// Convert price to satoshi for check
$price = USDtoBTC($price);
$price = $price *100000000;

// Expired
if($status < 0){
    exit();
}


if($value >= round($price)){
    // Update invoice status
    updateInvoiceStatus($code, $status);
    if($status == 2){
        // Correct amount paid and fully confirmed
        // Do whatever you want here once payment is correct
        $invoice = getInvoice($addr);
        createOrder($invoice, getInvoiceIp($addr));
    }
}else {
    // Buyer hasnt paid enough
    updateInvoiceStatus($code, -2);
}
?>

Inside this endpoint, we should update our database with the new status of the given payment. The updateInvoiceStatus function does this job and it takes two parameters. The code which is the unique identifier of each payment and second is the status value. To find the code, we use address because each payment has or should have a unique address. It is strongly advised to NOT reuse your bitcoin address.

Blockonomics WebSocket

Blockonomics provide websockets, so your application (client) can get instant update on the status of any transaction and provide relevant view of the application as a next step. The websocket is implemented on the invoice.php page because the user will perform the transaction on this page and thus, we would like to know when the user does the transaction. Upon receiving status update from the websocket, we can conclude that user has completed the transaction. This does not guarantee that you have received your payment. Please use HTTP CallBack URL endpoint to update the staus of the transaction and from this checkout page, DO NOT show that your payment is successful, until it is confirmed by the CallBack Endpoint.

    <script>
        var status = <?php echo $statusval; ?>
        
        // Create socket variables
        if(status < 2 && status != -2){
        var addr =  document.getElementById("address").innerHTML;
        var wsuri2 = "wss://www.blockonomics.co/payment/"+ addr;
        // Create socket and monitor
        var socket = new WebSocket(wsuri2, "protocolOne")
            socket.onmessage = function(event){
                console.log(event.data);
                response = JSON.parse(event.data);
                //Refresh page if payment moved up one status
                if (response.status > status)
                  setTimeout(function(){ window.location=window.location }, 1000);
            }
        }
        
    </script>